1. 程式人生 > 其它 >Codeforces Round #780 (Div.2) A-F2 完整題解

Codeforces Round #780 (Div.2) A-F2 完整題解

好簡單的一場,但我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<<'
\n'; else cout<<1<<'\n'; } }
View Code

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;
        
for(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"; } }
View Code

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)。