Codeforces Round #646 (Div. 2)(A—E)题解

好久没写题解了,忙里偷闲来摸一摸。

A Odd Selection

日常A乱WA系列,没奇数必定不行,先扔了,然后贪心搞一下,先把 x x x全填成偶数,然后看能否扔进去奇数个奇数即可。

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#pragma comment(linker, "/STACK:1024000000,1024000000")
il ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}
const int N =1e5+5;
const int MAX=1e9;
const int mod = 1e9+7;
#define db double
#define eps 1e-8
int a[N];
signed main() {
    int t=read();
    while(t--){
        int l=0,r=0;
        int n=read(),x=read();
        for (int i = 1; i <=n ; ++i) {
            a[i]=read();
            if(a[i]%2!=0)l++;
            else r++;
        }
        if(l==0){
            cout<<"No"<<endl;
        }else{
            if(r>=x){
                cout<<"Yes"<<endl;
            }else{
                x-=r;
                if(x%2!=0)cout<<"Yes"<<endl;
                else if(x%2==0&&r!=0&&x+1<=l){
                    cout<<"Yes"<<endl;
                }else{
                    cout<<"No"<<endl;
                }
            }
        }
    }
    return 0;
}

B Subsequence Hate

维护一个前缀和后缀,分别计算0/1个数,之后遍历看看那种刷法省钱即可(10,01,00,11)

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#pragma comment(linker, "/STACK:1024000000,1024000000")
il ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}
const int N =1e3+5;
const int MAX=1e9;
const int mod = 1e9+7;
#define db double
#define eps 1e-8
int pre[2][N],suf[2][N];
signed main() {
    int t=read();
    while(t--){
        char s[2020];
        cin>>(s+1);
        memset(pre,0, sizeof(pre));
        memset(suf,0, sizeof(suf));
        int len=strlen(s+1);
        for (int i = 1; i <=len ; ++i) {
            pre[0][i]=pre[0][i-1]+(s[i]=='0');
            pre[1][i]=pre[1][i-1]+(s[i]=='1');
        }
        for (int i = len; i >=1 ; --i) {
            suf[0][i]=suf[0][i+1]+(s[i]=='0');
            suf[1][i]=suf[1][i+1]+(s[i]=='1');
        }
        int ans=len;
        for (int j = 1; j <=len ; ++j) {
            ans=min(ans,pre[1][j]+suf[0][j+1]);
            ans=min(ans,pre[0][j]+suf[1][j+1]);
            ans=min(ans,pre[0][j]+suf[0][j+1]);
            ans=min(ans,pre[1][j]+suf[1][j+1]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

C Game On Leaves

如果目标节点不是叶子节点,必输的情况就是仅剩三个节点并且目标节点在中间。那么只需要判断 n − 3 n-3 n3的奇偶性即可。

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#pragma comment(linker, "/STACK:1024000000,1024000000")
il ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}
const int N =1e3+5;
int d[N];
signed main() {
    int t=read();
    while(t--){
        int n=read(),x=read();
        for (int j = 0; j <=n ; ++j)d[j]=0;
        for (int i = 0; i <n-1 ; ++i) {
            int u=read(),v=read();
            d[u]++; d[v]++;
        }
        if(d[x]<=1){
            cout<<"Ayush"<<endl;
        }else{
            n-=3;
            if(n%2!=0){
                cout<<"Ayush"<<endl;
            }else{
                cout<<"Ashish"<<endl;
            }
        }
    }
    return 0;
}

D Guess The Maximums

看到12次很明显就是二分了。
直接二分询问即可。如果数列的最大值是 max ⁡ \max max,那么密码至少有 n − 1 n-1 n1位是 max ⁡ \max max,我们只需要二分询问那个子集中最大值是 max ⁡ \max max即可。然后再询问除该子集之外的最大值就是这一位的密码。有点找假金币的感觉==

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#pragma comment(linker, "/STACK:1024000000,1024000000")
il ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}
const int N =1e3+5;
const int MAX=1e9;
const int mod = 1e9+7;
#define db double
#define eps 1e-8
vector<int> g[N];
bitset<N> bit[N];
int n,k;
int ma;
int query(int l,int r){
    int sz=0;
    for (int i = l; i <=r ; ++i) {
        sz+=g[i].size();
    }
    cout<<"? "<<sz<<" ";
    for (int j = l; j <=r ; ++j) {
        for(int i:g[j])cout<<i<<" ";
    }
    cout.flush();
    int ans;
    cin>>ans;
    return ans;
}int vis[1010];
void solve(){
    cout<<"? "<<n<<" ";
    for (int i = 1; i <=n ; ++i) {
        cout<<i<<" ";
    }
    cout.flush();
    cin>>ma;
    int tmp=ma+1;
    int l=1,r=k;
    while(l<r){
        int mid=(l+r)>>1;
        tmp=query(l,mid);
        if(tmp==ma){
            r=mid;
        }else{
            l=mid+1;
        }
    }
    memset(vis,0, sizeof(vis));
    for (int m : g[l]) {
        vis[m]=1;
    }
    vector<int> tm;
    for (int i1 = 1; i1 <=n ; ++i1) {
        if(!vis[i1]){
            tm.push_back(i1);
        }
    }
    cout<<"? "<<tm.size()<<" ";
    for (int i:tm) {
        cout<<i<<" ";
    }
    cout.flush();
    cin>>tmp;
    cout<<"! ";
    for (int j = 1; j <=k ; ++j) {
        if(l!=j)cout<<ma<<" ";
        else cout<<tmp<<" ";
    }
}
signed main() {
    int t=read();
    while(t--){
        n=read(),k=read();
        for (int i = 1; i <=k ; ++i) {
            g[i].clear();
            int tmp=read();
            while(tmp--){
                int a=read();
                g[i].push_back(a);
            }
        }
        solve();
        string s;
        cin>>s;
        if(s=="Correct")continue;
        else return 0;
    }
    return 0;
}

E Tree Shuffling

如果某个节点的费用大于其父亲结点,显然选父亲比选它更优。考虑先 d f s dfs dfs一波保证每个节点的费用 t r [ x ] tr[x] tr[x]满足 t r [ x ] = min ⁡ ( t r [ x ] , t r [ f a ] ) , f a tr[x]=\min(tr[x],tr[fa]),fa tr[x]=min(tr[x],tr[fa]),fa x x x的父亲结点。然后对于每个节点,假设其当前需要刷 k k k个节点,显然有 k = 2 ∗ min ⁡ ( d i f 1 [ x ] , d i f 2 [ x ] ) k=2*\min(dif1[x],dif2[x]) k=2min(dif1[x],dif2[x]),其中 d i f 1 , d i f 2 dif1,dif2 dif1,dif2分别代表 01 01 01 10 10 10类型。如果 x x x比其父亲结点费用要小,那就没必要向上传递了,记录当前节点费用,然后在其父亲结点的两个 d i f dif dif值里减去 k k k,否则就把当前节点的 k k k向上传递,然后令 k = 0 k=0 k=0

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#pragma comment(linker, "/STACK:1024000000,1024000000")
il ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}
const int N =2e5+5;
const int MAX=1e9;
const int mod = 1e9+7;
#define db double
#define eps 1e-8
#define int long long
int d[N],sz[N];
struct edge{
    int u,v,w,nxt;
}e[N*2];
int head[N],cnt,dif1[N],dif2[N];
void add(int u,int v,int w){
    e[cnt]={u,v,w,head[u]};
    head[u]=cnt++;
}
struct node{
    int a,b,c;
}tr[N];
int work[N];
void dfs(int x,int fa){
    if(tr[x].b>tr[x].c){
        dif1[x]++;
    }else if(tr[x].b<tr[x].c){
        dif2[x]++;
    }
    tr[x].a=min(tr[fa].a,tr[x].a);
    for (int i = head[x]; i !=-1 ; i=e[i].nxt) {
        int v=e[i].v;
        if(v!=fa){
            dfs(v,x);
            dif1[x]+=dif1[v];
            dif2[x]+=dif2[v];
        }
    }

    work[x]=2*min(dif1[x],dif2[x]);
    if(tr[x].a<tr[fa].a){
        dif1[fa]-=work[x]/2;
        dif2[fa]-=work[x]/2;
    }else{
        work[x]=0;
    }
}
signed main() {
    memset(head,-1, sizeof(head));
    int n=read(),l=0,r=0;
    for (int i = 1; i <=n ; ++i) {
        tr[i].a=read();tr[i].b=read();tr[i].c=read();
        if(tr[i].b>tr[i].c)l++;
        else if(tr[i].c>tr[i].b)r++;
    }

    if(l!=r){cout<<"-1";return 0;}
    for (int j = 0; j <n-1 ; ++j) {
        int u=read();int v=read();
        add(u,v,1);
        add(v,u,1);
    }
    tr[0].a=100000000000;
    dfs(1,0);//cout<<dif1[1]<<" "<<dif2[1]<<endl;
    int ans=0;
    for (int k = 1; k <=n ; ++k) {
        ans+=work[k]*tr[k].a;
    }
    cout<<ans;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值