Starters 109 Division 2 (Rated)

比赛录屏

https://www.bilibili.com/video/BV1Aw411n7DP/?vd_source=9a4bbd69c77feaab80f2e4e19721de57vd_source=9a4bbd69c77feaab80f2e4e19721de57

\(Best of N Sets\)

https://www.codechef.com/viewsolution/1031196498

\(Minimum XOR\)

https://www.codechef.com/viewsolution/1031202227

\(Alter Ego\)

https://www.codechef.com/viewsolution/1031240608

\(Chroma Swap\)

题意:给定长度为 \(n\) 的两个数组,再给每个数字一个颜色。可以交换任意次 \(A\) 数组和 \(B\) 数组中相同颜色的数字,能否使得 \(A\) 数组不下降。
解法:其实这道题很显然,两个数组中的相同颜色属于同一个 \(set\) ,每次贪心地选择当前颜色的 \(set\) 能选的最小的。就这样本人wa到了比赛结束,为什么呢?因为如果 \(A\) 数组中的某个颜色在 \(B\) 数组中没有出现过,那么 \(A\) 数组的相同颜色也是不能交换的。

vector<int>col[N];
int a[N],b[N],p[N],idx[N],inb[N];
void solve(){
    int n=read();
    for(int i=0;i<=2*n;i++){
        col[i].clear();
        idx[i]=0;
        inb[i]=0;
    }
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1;i<=n;i++){
        p[i]=read();
        col[p[i]].push_back(a[i]);
    }
    for(int i=1;i<=n;i++){
        b[i]=read();
    }
    for(int i=1;i<=n;i++){
        int x=read();
        col[x].push_back(b[i]);
        inb[x]=1;
    }
    for(int i=0;i<=2*n;i++){
        sort(col[i].begin(),col[i].end());
    }
    int lst=-1;
    for(int i=1;i<=n;i++){
        int now=p[i];
        if(!inb[now]){
            if(a[i]<lst){
                cout<<"No\n";
                return ;
            }else{
                lst=a[i];
                continue;
            }
        }
        while(idx[now]<col[now].size()&&col[now][idx[now]]<lst){
            idx[now]++;
        }
        if(idx[now]>=col[now].size()){
            cout<<"No\n";
            return  ;
        }else{
            lst=col[now][idx[now]];
            idx[now]++;
        }
    }
    cout<<"Yes\n";
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}

\(Rigged Game\)

题意:给定一棵 \(n\) 个节点的树,规定选择一个节点 \(x,1 \le x\le n\) ,所有到 \(x\) 的最短路径小于 \(y,0 \le y\le n-1\) 的节点权值和为 \(k\) 。给定一些权值,你可以任意分配这些权值为点权。在对整张图,任意选择 \(x,y\) 时,\(k\) 的最小期望是多少。

场上这题题意读错了,读成了任意选择两个点, \(k\) 为简单路径上的和(扔进Pool)。

解法:这里有两件事要做:计算出所有 \(x,y\) 的权值和与找出最佳分配。对于第二件事,显然我们要把遍历次数最多的点赋更大的权值。而处理第一个问题,怎么看都是换根 \(dp\)\(dfs1\) 时需要得到一个点被遍历的次数,\(dfs2\) 时换根得到整棵树每个节点的被遍历次数,而事实上题解采取的是维护不会被遍历的次数。

//赛时这道题好像一开始是D 然后变成E 结束再看变成了F
vector<int>G[N];
int disum[N],subsz[N];
void dfs1(int u ,int fa){
    subsz[u]=1;
    for(auto v:G[u]){
        if(v==fa) continue;
        dfs1(v,u);
        disum[u]+=disum[v]+subsz[v];
        subsz[u]+=subsz[v];
    }
}
void dfs2(int u,int fa,int add,int n){
    for(auto v:G[u]){
        if(v==fa) continue;
        dfs2(v,u,add+disum[u]-(disum[v]+subsz[v])+n-subsz[v],n);
    }
    disum[u]+=add;
}
int qmi(int m, int k, int p){
    int res = 1 % p, t = m;
    while (k){
        if (k&1) res = res * t % p;
        t = t * t % p;
        k >>= 1;
    }
    return res;
}
void solve(){
    int n=read(),ans=0;
    for(int i=1;i<=n;i++){
        subsz[i]=0;
        disum[i]=0;
        G[i].clear();
    }
    vector<int>w(n+1);
    for(int i=1;i<=n;i++){
        w[i]=read();
    }
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        G[x].push_back(y);
        G[y].push_back(x);
    }
    dfs1(1,-1);
    dfs2(1,-1,0,n);
    sort(disum+1,disum+1+n);
    sort(w.begin()+1,w.end());
    for(int i=1;i<=n;i++){
        ans+=(n*n-disum[i])%mod*w[i]%mod;
        ans%=mod;
    }
    ans=ans*qmi(n,mod-2,mod)%mod*qmi(n,mod-2,mod)%mod;
    cout<<ans<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}
posted @ 2023-11-23 00:41  EdGrass  阅读(27)  评论(0)    收藏  举报