1. 程式人生 > 實用技巧 >Codeforces Round #659 (Div. 2)【ABCD】(題解)

Codeforces Round #659 (Div. 2)【ABCD】(題解)

涵蓋知識點:思維、博弈

比賽連結:傳送門

A - Common Prefixes

題意: 構造\(n+1\)個字串使得第\(i\)個和第\(i+1\)個字串的最長公共字首的長度為\(a_i\)
題解: 一開始全a,後面隨便改一改。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
int a[maxn];
int main(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        string s(55,'a');
        cout<<s<<"\n";
        for(int i=1;i<=n;i++){
            s[a[i]]++;
            if(s[a[i]]=='z'+1)s[a[i]]='a';
            cout<<s<<"\n";
        }
    }
    return 0;
}

B2 - Koa and the Beach (Hard Version)

題意: 共有\(n\)片海域,初始深度分別給定。潮汐會以\(2k\)為週期上下波動影響深度,前\(k\)秒以\(1m/s\)的速度加深,後\(k\)秒以\(1m/s\)速度變淺。每一秒都可以選擇呆在當前海域或前往下一海域,但是當深度大於\(l\)時就會淹死。問能否到達最後的終點。
題解: 確定所有深度加\(k\)小於等於\(l\)的點為安全區,可以在任意的安全區停留任意長的時間。然後儘可能選擇最早的不會淹死的時間進入下一節點。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
int d[maxn];
int main(){
    int t;cin>>t;
    while(t--){
        int n,k,l;
        cin>>n>>k>>l;
        vector<int> safe={0};
        for(int i=1;i<=n;i++){
            cin>>d[i];
            if(d[i]+k<=l)safe.push_back(i);
        }
        safe.push_back(n+1);
        bool flag=true;
        for(int i=1;i<safe.size()&&flag;i++){
            int tide=k,down=-1;
            for(int j=safe[i-1]+1;j<safe[i];j++){
                tide+=down;
                if(down==-1)tide-=max(0,d[j]+tide-l);
                if(tide<0||d[j]+tide>l){flag=false;break;}
                if(tide==0)down=1;
            }
        }
        puts(flag?"Yes":"No");
    }
    return 0 ;
}

C - String Transformation 1

題意: 給定兩個字串,每次可以選擇一個字母然後把\(a\)中所有的那個字母變為比他大的另一個字母,問最少幾次能把\(a\)變為\(b\)
題解: 貪心,直接按照需求從小到大模擬一遍。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=20;
int c[maxn][maxn];
int main(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        string a,b;
        cin>>a>>b;
        memset(c,0,sizeof c);
        int ans=0;
        for(int i=0;i<n;i++){
            if(a[i]>b[i]){
                puts("-1");
                goto st;
            }
            c[a[i]-'a'][b[i]-'a']++;
        }
        for(int i=0;i<19;i++){
            int tmp=21;
            for(int j=i+1;j<20;j++){
                if(c[i][j])tmp=min(tmp,j);
            }
            if(tmp!=21){
                ans++;
                for(int j=i+1;j<20;j++){
                    c[tmp][j]+=c[i][j];
                }
            }
        }
        cout<<ans<<"\n";
        st:;
    }
    return 0;
}

D - GameGame

題意: 博弈,兩人拿數,異或值大的勝。
題解: 若所有值的異或值\(sum\)\(0\)則平局。否則只要判斷\(sum\)的最高位。問題轉化為誰拿走了奇數個最高位的數字就獲勝。如果數字的個數為偶數個,那麼最後一次拿的人是後手,顯然先手必勝,只要先取一個符合要求的接下來模仿對手即可。接下來考慮數字個數為奇數的情況,若含最高位的數字個數對\(4\)取模結果為\(1\),那麼先手可以先取一個含最高位的數字,接下來模仿對手的操作。否則先後手交換。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int a[maxn],cnt[2];
int main(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        int sum=0;
        for(int i=0;i<n;i++){
            cin>>a[i];
            sum^=a[i];
        }
        if(sum==0){
            puts("DRAW");
            continue;
        }
        int b=1<<(31-__builtin_clz(sum));
        memset(cnt,0,sizeof cnt);
        for(int i=0;i<n;i++)cnt[bool(a[i]&b)]++;
        if(cnt[1]%4==1||n%2==0)puts("WIN");
        else puts("LOSE");
    }
    return 0;
}