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"); } } }
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"); } }
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(); } }
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; } }
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(); } }
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"); } }
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; } }