Codeforces Round #780 (Div.2) A-F2 完整題解
阿新 • • 發佈:2022-04-01
好簡單的一場,但我C題寫了一小時,E題寫了40min
我是啥b 總之開講
A. Vasya and Coins
如果你沒有硬幣1,ans=1
否則ans=你的購買力+1
#include<bits/stdc++.h> using namespace std; const int N=200010; int a[4][N]; int main(){ int t;cin>>t; while(t--){ int a,b;cin>>a>>b; if(a!=0)cout<<a+b+b+1<<'View Code\n'; else cout<<1<<'\n'; } }
B. Vlad and Candies
theshy來全吃了
只吃最多的,而且不能連吃兩個一樣的
思考一下發現最大值與次大值相差小於1就行。
#include<bits/stdc++.h> using namespace std; const int N=200010; int a[N]; int main(){ int t;cin>>t; while(t--){ int n;cin>>n;View Codefor(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+n+1); if(a[n]-a[n-1]<=1)cout<<"YES\n"; else cout<<"NO\n"; } }
C. Get an Even String
法1:貪心
掃一遍,誰先配上對就取那一對
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int聰明人都寫這種N=200007; int main() { int t;cin>>t; int cnt[26]; while (t--){ memset(cnt,0,sizeof cnt); string s;cin>>s; int x=0; for(auto c:s){ if(cnt[c-'a']){ x+=2;for(int i=0;i<26;i++)cnt[i]=0; } else cnt[c-'a']++; }cout<<s.size()-x<<'\n'; } return 0; }
法2:dp
啥B才寫dp,比如我
考慮向右轉移和向下一個相同字元(需要預處理)轉移,同時把所有答案轉移到n上作為結果
dp第二維的1表示這個字元消掉了,0表示沒消掉
#include<bits/stdc++.h> using namespace std; const int N=200010; int ne[N],dp[N][2]; queue<int>sx[26]; int main(){ int t;cin>>t; while(t--){ string s;cin>>s; int n=s.size(); s=' '+s; for(int i=1;i<=n;i++){ dp[i+1][0]=dp[i+1][1]=2e9; sx[s[i]-'a'].push(i); }dp[1][1]=1,dp[1][0]=0; for(int i=0;i<26;i++){ while(!sx[i].empty()){ int f=sx[i].front();sx[i].pop(); if(sx[i].empty())break; ne[f]=sx[i].front(); } } for(int i=1;i<=n;i++){ dp[n][0]=min(dp[n][0],min(dp[i][0]+n+1-i,dp[i][1]+n-i)); if(ne[i]!=0)dp[ne[i]][1]=min(dp[ne[i]][1],dp[i][0]+ne[i]-i-1); dp[i+1][0]=min({dp[i+1][0],dp[i][0]+1,dp[i][1]}); } cout<<min(dp[n+1][1],dp[n+1][0])<<'\n'; fill(ne,ne+n+3,0); } }別學,學了會變傻的
D. Maximum Product Strikes Back
一段如果包含0,那它肯定不會大;所以把陣列分成很多不含0的段
因為2的冪次不會減,對於每一段考慮貪心,如果整段乘起來大於零是最好的,否則分別不斷去掉左(右)邊的數,直到值變成正的。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=200007; int a[N]; int zer[N],tot;//零的個數 int main() { int t;cin>>t; while (t--){tot=0; int n;cin>>n; for(int i=1;i<=n;i++){ cin>>a[i];if(!a[i])zer[++tot]=i; }zer[++tot]=n+1;//0和-1的位置也要加上 int al=0,ar=0,m=0;//左右端點,最大值的次數 for(int i=1;i<=tot;i++){ int ans=1,fh=1;//次數和符號 for(int j=zer[i-1]+1;j<zer[i];j++){ if(a[j]<0)fh*=-1; if(abs(a[j])>1)ans++; } if(fh>0&&m<ans)m=ans,ar=zer[i],al=zer[i-1]; if(fh<0&&m<ans){ int anss=ans; for(int j=zer[i-1];j<zer[i];j++){ if(abs(a[j])>1)anss--; if(a[j]<0){ if(m<anss)m=anss,al=j,ar=zer[i]; break; } }anss=ans; for(int j=zer[i]-1;j>zer[i-1];j--){ if(abs(a[j])>1)anss--; if(a[j]<0){ if(m<anss)m=anss,ar=j,al=zer[i-1]; } } } } cout<<al<<' '<<n+1-ar<<'\n'; } return 0; }很暴力
E. Matrix and Shifts
容易發現四種操作本質上是一種操作
也就是說,一斜行的零變成1,其它斜行的1變成0。我們暴力一下就做完啦。
#include<bits/stdc++.h> using namespace std; const int N=200010; int a[N]; int main(){ int t;cin>>t; while(t--){ int n;cin>>n; fill(a,a+n+3,0); for(int i=1;i<=n;i++){ string s;cin>>s; for(int j=1;j<=n;j++)a[(i-j+n)%n]+=s[j-1]-48; }int ans=0; for(int i=0;i<n;i++)ans+=a[i]; int anss=n*n; for(int i=0;i<n;i++)anss=min(anss,ans-a[i]+n-a[i]); cout<<anss<<'\n'; } }view shabby code
F2&F1. Promising String
我們令cnt值為子段中-的個數減去+的個數
每次操作少兩個減號多一個加號,所以一個操作可以讓cnt變成cnt-3;
我們不用考慮是否有相鄰的-,因為我們只會去對cnt>=3的子段進行操作;這個時候必然有兩個相鄰的減號。
所以分別對於cnt模3餘0、1、2的字首,用樹狀陣列操作一通就行了(我們只考慮cnt值小於等於當前cnt值的數),複雜度O(nlogn)。