Codeforces Round #697 (Div. 3)题解报告(A-G)

考完雅思了开始康复训练...争取以后每把都打不咕。

A.Odd Divisor

Editorial:偶数有个特性就是可以一直除2,所以我们只需要判断无限除2之后的奇数是不是1即可。

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int main(){
    int T;scanf("%d",&T);
    while(T--){
        ll n;scanf("%lld",&n);
        if(n%3==0){puts("YES");continue;}
        while(n%2==0){
            n/=2;
        }
        if(n==1){puts("NO");continue;}
        if(n%2==1){
            puts("YES");
        }else{
            puts("NO");
        }
    }
}
View Code

 

B. New Year's Number

Editorial:先尽可能把2020减去,最后会发现一些多余的数,这个时候对多余的数特判,看是否多余2020的组数即可。

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n;scanf("%d",&n);
        int d=n/2020;
        int re=n-d*2020;
        if(re>d) puts("NO");
        else puts("YES");
    }
}
View Code

 

C. Ball in Berland

Editorial:这个题刚拿到手我就想二分图做法(划掉),但是发现好像不太容易维护边与边之间的关系所以叉掉。 于是正确做法是统计a和b每个人在预配对中的数量,然后O(n)扫一遍枚举统计,因为不可能出现2组a和b都是同一个人的情况,所以mp[a]就代表和a挂钩的人,同理mp[b]代表和b挂钩的人,这时候要处理的时候记得+1,因为a和b自己有搭班。所以最后的时候就把这些结果加起来就ok啦。

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
int a[maxn],b[maxn];
map<int,int> mp1,mp2; 
int main(){
    IO;
    int T;scanf("%d",&T);
    while(T--){
        int x,y,n;scanf("%d%d%d",&x,&y,&n);
        rep(i,1,n) scanf("%d",&a[i]),mp1[a[i]]+=1;
        rep(i,1,n) scanf("%d",&b[i]),mp2[b[i]]+=1;
        ll ans=0;
        rep(i,1,n){
            ans+=(n-mp1[a[i]]-mp2[b[i]]+1);
        }
        cout<<ans/2<<endl;
        mp1.clear();mp2.clear();        
    }
}
View Code

 

D. Cleaning the Phone

Editorial:这个题比赛的时候没写出来qwq想着用背包去做但是背包背不下那么大的数据所以肯定得用贪心啦。做法就是对价格为1和2的分别从大到小排序之后分别预处理,以价值2的为例,肯定越往前单个体积越大,所以在每一次处理的时候二分寻找适合的最低的a就行(双指针也可以,因为方向是恒定的),还有记得开ll,扫的时候要从0开始扫

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
int a[maxn],b[maxn];
ll pre1[maxn],pre2[maxn];
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n,m;ll tot=0;scanf("%d%d",&n,&m);
        rep(i,1,n) scanf("%d",&a[i]),tot+=a[i];
        rep(i,1,n) scanf("%d",&b[i]);
        if(tot<m){puts("-1");continue;}
        vector<int> vec1,vec2;
        rep(i,1,n){
            if(b[i]==1) vec1.pb(a[i]);
            else vec2.pb(a[i]);
        }
        sort(vec1.rbegin(),vec1.rend());
        sort(vec2.rbegin(),vec2.rend());
        int cnt1=0,cnt2=0;
        for(auto it:vec1){
            pre1[++cnt1]=pre1[cnt1-1]+it;
        }
        for(auto it:vec2){
            pre2[++cnt2]=pre2[cnt2-1]+it;
        }
        ll ans=inf;
        for(int i=0;i<=cnt2;i++){
            int remain=m-pre2[i];
            ll pos=lower_bound(pre1,pre1+cnt1+1,remain)-pre1;
            if(pre2[i]+pre1[pos]>=m) ans=min(ans,2*i+pos);
        }
        printf("%lld\n",ans);
        rep(i,1,n) pre1[i]=0,pre2[i]=0;
    }
}
View Code

 

E. Advertising Agency

Editorial:读完题就看出很裸的卢卡斯板子题,感觉没什么好讲的。

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int a[maxn];map<int,int> mp,vis;
bool cmp(int a,int b){
    return a>b;
}
ll mulit(ll a,ll b,ll m){
    ll ans=0;
    while(b){
        if(b&1) ans=(ans+a)%m;
        a=(a<<1)%m;
        b>>=1;
    }
    return ans;
}

ll quick_mod(ll a,ll b,ll m){
    ll ans=1;
    while(b){
        if(b&1){
            ans=mulit(ans,a,m);
        }
        a=mulit(a,a,m);
        b>>=1;
    }
    return ans;
}

ll comp(ll a,ll b,ll m){
    if(a<b) return 0;
    if(a==b) return 1;
    if(b>a-b) b=a-b;
    ll ans=1,ca=1,cb=1;
    for(int i=0;i<b;i++){
        ca=ca*(a-i)%m;
        cb=cb*(b-i)%m;
    }
    ans=ca*quick_mod(cb,m-2,m)%m;
    return ans;
}

ll lucas(ll a,ll b,ll m){
    ll ans=1;
    while(a&&b){
        ans=(ans*comp(a%m,b%m,m))%m;
        a/=m;
        b/=m;
    }
    return ans;
}

int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n,k;scanf("%d%d",&n,&k);
        set<int> s;map<int,int>cnt;
        rep(i,1,n) scanf("%d",&a[i]),mp[a[i]]+=1;
        sort(a+1,a+n+1,cmp);
        rep(i,1,k){
            s.insert(a[i]);
            cnt[a[i]]+=1;
        }
        ll ans=1;
        for(auto it:s){
            ans*=lucas(mp[it],cnt[it],mod);
        }
        cout<<ans<<endl;
        mp.clear();vis.clear();
    }
}
View Code

 

F.Unusual Matrix

Editorial:感觉是这套div3里思维含量最大的题了。其实仔细想想,a[i][j]的变动可能会对a[1][j]或者a[i][1]造成影响,但是呢有些时候又可以通过a[1][1]变回来。这里我要介绍一种我自己想的最简单容易理解的方法。首先我们先直接把a[i][j]和b[i][j]取XOR操作,得到c[i][j],这里我要提的一点是a要变成b,必须借c之手。所以我们现在要想的是怎么把c[i][j]变成0,那其实很简单,只需要维护刚刚我说的4个点。把他单独领出来会发现这4个点中如果有奇数个c[i][j]那肯定无法转化。所以只需要特判单偶性就行。

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e3+5;
int a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n;scanf("%d",&n);
        rep(i,1,n) rep(j,1,n) scanf("%1d",&a[i][j]);
        rep(i,1,n) rep(j,1,n) scanf("%1d",&b[i][j]);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                c[i][j]=a[i][j]^b[i][j];
            }
        }
        bool flag=true;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if((c[i][j]+c[1][1]+c[1][j]+c[i][1])%2==1){
                    flag=false;
                    goto end;
                }
            }
        } 
        end:;
        if(flag) puts("YES");
        else puts("NO");
    }
}
View Code

 

G.Strange Beauty

Editorial:考察的是对素数筛的理解。这里我用的是埃式筛,复杂度O(nlogn),只需要统计每个数他往下有几个可行的数,然后维护最大ans,最后输出n-ans即可

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n;scanf("%d",&n);
        vector<int> cnt(maxn),dp(maxn);
        rep(i,1,n){
            int x;scanf("%d",&x);
            cnt[x]+=1;
        }         
        int ans=0;
        rep(i,1,2e5){
            dp[i]+=cnt[i];
            for(int j=2*i;j<=2e5;j+=i){
                dp[j]=max(dp[j],dp[i]);
            }
            ans=max(ans,dp[i]);
        }
        cout<<n-ans<<endl;
    }
}
View Code

 

posted @ 2021-01-26 12:19  Anonytt  阅读(175)  评论(0编辑  收藏  举报