Codeforces Round #702 (Div. 3) 题解

A

分析:

直接模拟,对于相邻的两个数,如果小的两倍还是比大的小,就乘2,同时贡献++。

代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>

using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

int a[55];
int n;
int cal(int idx){
    int maxv=max(a[idx],a[idx+1]);
    int minv=min(a[idx],a[idx+1]);

    int cnt=0;
    while(minv*2<maxv) {minv*=2;cnt++;}

    return cnt;

}

int main(){
    int T; cin>>T;
    while(T--){
        cin>>n;
        FOR(i,1,n) cin>>a[i];
        
        int cnt=0;
        FOR(i,1,n-1) cnt+=cal(i);

        cout<<cnt<<endl;
    }
    return 0;
}

B

分析:

统计出 \(mod3\) 三种余数的个数。然后对小于 \(n/3\) 个数的多少进行分类讨论:
若个数为 \(0\) ,即最小的个数也是 \(n/3\) ,那么无需做任何操作。
若个数为 \(1\) ,那么要让两个多的给那个少的补上,并统计贡献。
若个数为 \(2\) ,那么要让多的给两个少的补上,并统计贡献。

即:

        FOR(i,1,n){
            cin>>a[i];
            a[i]%=3;
            cnt[a[i]]++;
        }
        int minv=INF;
        FOR(i,0,2) minv=min(minv,cnt[i]);

        if(minv==n/3){
            cout<<0<<endl;
            continue;
        }

        int res=0;

        int cal=0;

        FOR(i,0,2){
            if(cnt[i]<n/3) cal++;
        }

        if(cal==1){
            int idx;
            FOR(i,0,2)
                if(cnt[i]<n/3) idx=i;
            res+=cnt[(idx+2)%3]-n/3 + 2*(cnt[(idx+1)%3]-n/3);
        }

        else if(cal==2){
            int idx;
            FOR(i,0,2)
                if(cnt[i]>n/3) idx=i;

            res+=n/3-cnt[(idx+1)%3] + 2*(n/3-cnt[(idx+2)%3]);
        }

        cout<<res<<endl;
代码
#pragma GCC optimize("O3")

#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

int a[30005];
int cnt[3];
int main(){
    int T; cin>>T;
    while(T--){
        SET0(cnt);
        int n; cin>>n;
        FOR(i,1,n){
            cin>>a[i];
            a[i]%=3;
            cnt[a[i]]++;
        }
        int minv=INF;
        FOR(i,0,2) minv=min(minv,cnt[i]);

        if(minv==n/3){
            cout<<0<<endl;
            continue;
        }

        int res=0;

        int cal=0;

        FOR(i,0,2){
            if(cnt[i]<n/3) cal++;
        }

        if(cal==1){
            int idx;
            FOR(i,0,2)
                if(cnt[i]<n/3) idx=i;
            res+=cnt[(idx+2)%3]-n/3 + 2*(cnt[(idx+1)%3]-n/3);
        }

        else if(cal==2){
            int idx;
            FOR(i,0,2)
                if(cnt[i]>n/3) idx=i;

            res+=n/3-cnt[(idx+1)%3] + 2*(n/3-cnt[(idx+2)%3]);
        }

        cout<<res<<endl;

    }
    return 0;
}

C

分析:

预处理出 \([1,1e4]\) 的所有立方数,问题即转化为求 \([1,1e4]\) 是否存在两个数满足它们的和为目标数。

代码
#pragma GCC optimize("O3")

#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

const int N=1e4+5;
set<ll> rec;
void init(){
    FOR(i,1,N)
        rec.insert((ll)i*i*i);
}
int main(){
    init();
    int T; cin>>T;
    while(T--){
        ll x; cin>>x;

        bool ok=0;
        for(auto i:rec){
            if(rec.find(x-i)!=rec.end()) ok=1;
        }

        if(ok) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

D

分析:

分治,求出 \([1,n]\) 中的最大值(根节点)所在下标 \(root\) ,然后继续处理 \([1,root-1]\)\([root+1,n]\) 的最大值(对应的下标即为 \(root\) 的左右节点),并且分别连边(建树)。

建树后从根节点跑一遍dfs求出每个节点深度即可。

代码
#pragma GCC optimize("O3")

#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

const int N=205;

int n;
int a[N];
struct node{
    int to,next;
}e[N];
int head[N],tot;
void add(int u,int v){e[tot].to=v;e[tot].next=head[u];head[u]=tot++;}

int d[N];

int solve(int l,int r){
    if(l==r) return r;
    if(l>r) return -1;

    int root;
    FOR(i,l,r){
        if(a[i]==*max_element(a+l,a+1+r)){
            root=i;
            break;
        }
    }

    int ls=solve(l,root-1);
    int rs=solve(root+1,r);

    if(ls!=-1) add(root,ls);
    if(rs!=-1) add(root,rs);

    return root;
}

void dfs(int u,int deg){
    d[u]=deg;
    if(head[u]==-1) return;

    for(int i=head[u];~i;i=e[i].next){
        int go=e[i].to;
        dfs(go,deg+1);
    }
}

int main(){
    int T; cin>>T;
    while(T--){
        tot=0;
        memset(head,-1,sizeof head);

        cin>>n;
        FOR(i,1,n) cin>>a[i];

        solve(1,n);

        int root;
        FOR(i,1,n)
            if(a[i]==n) root=i;

        dfs(root,0); // for depth

        FOR(i,1,n) cout<<d[i]<<' ';
        cout<<endl;
    }
    return 0;
}

E

分析:

排序,找到一个断点 \(idx\) ,使得即便是 \([1,idx-1]\) 的前缀和也比 a[idx] 小,那么 \(idx\) 之前的玩家必然无法获胜。最后记录一下 \([idx,n]\) 的玩家编号即可。

代码
#pragma GCC optimize("O3")

#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

const int N=2e5+5;
struct node{
    int id,v;
}a[N];

int b[N];
int n;

bool cmp(node a,node b){
    return a.v<b.v;
}

ll s[N];

int main(){
    int T; cin>>T;
    while(T--){
        cin>>n;
        FOR(i,1,n){
            cin>>a[i].v;
            a[i].id=i;
        }

        sort(a+1,a+1+n,cmp);

        FOR(i,1,n){
            s[i]=s[i-1]+a[i].v;
        }

        int idx=1;
        DWN(i,n,1){
            if(s[i-1]<a[i].v){
                idx=i;
                break;
            }
        }

        cout<<n-idx+1<<endl;

        int cnt=0;
        FOR(i,idx,n) b[cnt++]=a[i].id;

        sort(b,b+cnt);

        FOR(i,0,cnt-1) cout<<b[i]<<' ';
        cout<<endl;
    }
    return 0;
}

F

分析:

记录一下每个数对应的个数,然后从大到小进行排序,枚举断点 \(i\)\([1,i]\) 的数表示不需要删到 \(0\)\([i+1,tot]\) 的则全部删到 \(0\)。最后统计贡献并求最小值。

代码
#pragma GCC optimize("O3")

#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

const int N=2e5+5;
int n;
int buc[N];

int main(){
    int T; cin>>T;
    while(T--){
        map<int,int> f;
        cin>>n;
        FOR(i,1,n){
            int k; cin>>k;
            ++f[k];
        }
        
        int tot=0;
        for(auto i:f)
            buc[++tot]=i.second;
        
        sort(buc+1,buc+1+tot,greater<int>());

        int ans=INF;
        FOR(i,1,tot)
            ans=min(ans,n-i*buc[i]);
        
        cout<<ans<<endl;
    }
    return 0;
}
posted @ 2021-02-17 12:06  HinanawiTenshi  阅读(241)  评论(1编辑  收藏  举报