• Codeforces Round #646 (Div. 2)【ABCDE】(题解)


    涵盖知识点:树上dp、树上博弈、二分

    比赛链接:传送门

    A - Odd Selection

    题意: (n)张牌中选(k)张使得和为奇数
    题解: 奇偶判断直接上代码。
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    
    int main(){
        int t;cin>>t;
        while(t--){
            int n,x;
            int odd=0,even=0;
            cin>>n>>x;
            for(int i=0,v;i<n;i++){
                cin>>v;
                if(v&1)odd++;
                else even++;
            }
            if(odd&&even){
                if(n==x){
                    if(odd&1)puts("YES");
                    else puts("NO");
                }
                else puts("YES");
            }
            else{
                if((x&1)&&odd)puts("YES");
                else puts("NO");
            }
        }
        return 0;
    }
    
    

    B - Subsequence Hate

    题意: 给定(01)串,问最少改变几个字符可以使得不存在(010)(101)的子序列。
    题解: 利用前缀和顺序扫描一遍。
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    char s[1010];
    int pre[1010];
    const int inf=0x3f3f3f3f;
    int main(){
        int t;cin>>t;
        while(t--){
            scanf("%s",s+1);
            int n=strlen(s+1);
            for(int i=1;i<=n;i++)pre[i]=pre[i-1]+(s[i]=='1');
            int ans=inf;
            for(int i=0;i<=n;i++){
                ans=min(ans,pre[i]+(n-i-(pre[n]-pre[i])));
                ans=min(ans,i-pre[i]+pre[n]-pre[i]);
            }
            cout<<ans<<"
    ";
        }
        return 0;
    }
    
    

    C - Game On Leaves

    题意: AB博弈,每次从树上取下一个叶子节点。谁先拿到树上标记为(x)的节点赢。
    题解: 特判(x)为叶子节点的情况。其他情况一定会拿到只剩三个节点且(x)为中间节点。判断奇偶性即可。
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    char s[1010];
    int pre[1010];
    const int inf=0x3f3f3f3f;
    int main(){
        int t;cin>>t;
        while(t--){
            int n,x;
            cin>>n>>x;
            int deg=0;
            for(int i=1,u,v;i<=n-1;i++){
                cin>>u>>v;
                if(u==x||v==x)deg++;
            }
            if(deg<=1)puts("Ayush");
            else{
                if(n&1)puts("Ashish");
                else puts("Ayush");
            }
        }
        return 0;
    }
    
    

    D - Guess The Maximums

    题意: 互动。有一个长度为(n)(1000以内)的数组(a)(未知),长度为(k)的不等长二维子集数组(s)(给出),且这(k)个数组完全不存在相同元素。所求密码的长度同样为(k)。现规定每位密码的值为(a)中的下标不在对应(s)中出现的最大值。形式上,((S_i underset{i eq j} cap S_j = emptyset)),(P_i = maxlimits_{j otin S_i} A[j])。现在每次询问可以给出一系列的下标,我们会得到所查询的所有下标的数组中值的最大值。要求在(12)次询问后得到正确的密码
    题解: 既然所有(s)独立,那么最多就只存在一个位置的密码不是(a)的最大值。(有可能全是最大值,因为(s)中可能不含最大值对应的下标。)所以我们先花(1)次来查询(n)个位置的最大值。然后二分搜索最大值所出现的位置。这里最多花费10次((2^{10}=1024))。最后一次我们用来查询这个位置的最大值就行了。
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef vector<int> vi;
    int query(vi q){
        cout<<"? "<<q.size()<<" ";
        for(auto i:q){
            cout<<i<<" ";
        }
        cout<<"
    ";
        cout.flush();
        int x;
        cin>>x;
        return x;
    }
    int main(){
        int t;cin>>t;
        while(t--){
            int n,k;
            cin>>n>>k;
            vector<vi> s(k);
            vi ans(k);
            for(int i=0,c;i<k;i++){
                cin>>c;
                s[i].resize(c);
                for(int j=0;j<c;j++)cin>>s[i][j];
            }
            vi q;
            for(int i=1;i<=n;i++)q.push_back(i);
            int mx=query(q);
            int l=0,r=k-1;
            while(l<r){
                int mid=(l+r)/2;
                q.clear();
                for(int i=0;i<=mid;i++){
                    for(auto j:s[i])q.push_back(j);
                }
                int x=query(q);
                if(x==mx)r=mid;
                else l=mid+1;
            }
            q.clear();
            vi vis(n+1);
            for(auto i:s[l])vis[i]=1;
            for(int i=1;i<=n;i++){
                if(!vis[i])q.push_back(i);
            }
            for(int i=0;i<k;i++){
                if(i==l)ans[i]=query(q);
                else ans[i]=mx;
            }
            cout<<"! ";
            for(auto i:ans){
                cout<<i<<" ";
            }
            cout<<"
    ";
            cout.flush();
            string correct;
            cin>>correct;
        }
        return 0;
    }
    
    

    E - Tree Shuffling

    题意: (n)结点的树编号为(1到n),根为(1)。每个节点的选取代价、当前值、目标值分别为(a_i,b_i,c_i)。当前值和目标值为(01)值。每次操作可以选取一个结点(u),在该节点的子树中任意选取(k)个结点重拍这些节点里面的数字,花费(k imes a_u)。求所有节点是否可达目标并求最小花费。
    题解: 首先处理一下数组(a)。它的值是他的所有可能祖先节点中的最小值。然后计算每一棵子树所需要交换的数量。多出来的丢给父亲节点来处理即可。
    Accept Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef vector<int> vi;
    const int maxn=2e5+10;
    vi edg[maxn];
    int a[maxn],b[maxn],c[maxn];
    typedef long long ll;
    ll ans=0;
    int dp[maxn][2];
    void dfs(int u,int p){
        if(p)a[u]=min(a[u],a[p]);
        for(auto v:edg[u]){
            if(v!=p){
                dfs(v,u);
                dp[u][0]+=dp[v][0];
                dp[u][1]+=dp[v][1];
            }
        }
        if(b[u]!=c[u])dp[u][b[u]]++;
        int mn=min(dp[u][0],dp[u][1]);
        ans+=2ll*mn*a[u];
        dp[u][0]-=mn;
        dp[u][1]-=mn;
    }
    int main(){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i]>>b[i]>>c[i];
        for(int i=1,u,v;i<=n-1;i++){
            cin>>u>>v;
            edg[u].push_back(v);
            edg[v].push_back(u);
        }
        dfs(1,0);
        if(dp[1][0]||dp[1][1])cout<<-1<<"
    ";
        else cout<<ans<<"
    ";
        return 0;
    }
    
    
  • 相关阅读:
    dda的fpga实现(转载)
    第四篇:数据预处理(一)
    第三篇:数据可视化
    第二篇:数据可视化
    第一篇:查阅数据
    RocketMQ集群部署记录
    使用k8s cronjob ,清除应用生成的日志文件
    使用HostAliases 添加pod 的/etc/hosts
    docker in docker 出现 libltdl.so.7 问题
    容器中JVM获取真实的CPU核数
  • 原文地址:https://www.cnblogs.com/charles1999/p/13026003.html
Copyright © 2020-2023  润新知