【学习笔记】CF1292E Rin and The Unknown Flower

题目太难,我想摆了。

这题咋做嘛,人脑搜索呗。

难就难在,如果第一步搜索就走错了,后面的步骤难度就大了。

如果询问单个字符,虽然这样字符集大小变成了 2 2 2,但是这一步花销太大了,以至于难以为继。

于是我们可以通过询问 C H , C O , H C , H O CH,CO,HC,HO CH,CO,HC,HO来代替,这一步花销是 1 1 1

如果有位置没有被确定,那么要么是 O ? O? O?,要么是两个相同字符。

我们分两种情况讨论。

1.1 1.1 1.1 如果所有位置都是 ? ? ?, 那么打表观察一下,我们发现此时字符集大小为 2 2 2,并且 O O O一定在字符集内。我们可以先询问 O O O OOO OOO,如果成功了就能确定一段前缀,再询问一次整个串长度即可。否则,我们可以再询问 H H H , C C C HHH,CCC HHH,CCC,能够确定出后缀长度。当 n = 4 n=4 n=4时我们还要额外询问一次整个串长度,有最大花费 1 + 1 3 + 1 16 < 1.4 1+\frac{1}{3}+\frac{1}{16}<1.4 1+31+161<1.4

1.2 1.2 1.2 如果有位置被确定出来了,考虑找到最右边的位置,比如是 ? ? . . . C H . . . ??...CH... ??...CH...,往后推非常容易,肯定都是 H H H,往前推的话,考虑有些不合法的情况可以被剪掉,因此只需要询问一次就能确定一位的答案,考虑最极端的情况, 1 + ∑ i = 3 50 1 i 2 < 1.4 1+\sum_{i=3}^{50}\frac{1}{i^2}<1.4 1+i=350i21<1.4 ,然后就做完了。如果是 ? ? . . . C O . . . ??...CO... ??...CO...呢?那么还是先往前面推,往后推的时候,就只能暴力试了,不过可以考虑先试 O O O,如果这一位还是 ? ? ?就只能是 C , H C,H C,H,那么后面就都可以确定了,因此可以通过。

如何做这种题做得更快一些?升级大脑呗。

#include
#define ll long long
#define pb push_back
#define db double
using namespace std;
int T,n;
string res;
string s[4]={"CH","CO","HC","HO"};
char ch[3]={'C','H','O'};
void ask(string s){
    cout<<"?"<<" "<<s<<endl;
    int k;cin>>k;
    for(int i=1;i<=k;i++){
        int x;cin>>x;
        for(int j=0;j<s.size();j++)res[x+j]=s[j];
    }
}
bool check(char x,char y){
    if(x=='C'&&y=='H'||x=='C'&&y=='O'||x=='H'&&y=='C'||x=='H'&&y=='O')return 1;
    return 0;
}
string solve(){
    for(int i=1;i<=n;i++)res[i]='?';
    for(int i=0;i<4;i++)ask(s[i]);
    int ok=0;
    for(int i=1;i<=n;i++)if(res[i]!='?')ok=1;
    if(!ok){
        ask("OOO");
        int ok2=0;
        if(res[1]!='?'){
            string tmp,tmp2;
            for(int i=1;i<=n;i++){
                if(res[i]!='?')tmp+=res[i];
                else tmp+='C';
            }
            ask(tmp);
            if(res[n]!='?'){
                return tmp;
            }
            for(int i=1;i<=n;i++){
                if(res[i]!='?')tmp2+=res[i];
                else tmp2+='H';
            }
            return tmp2;
        }
        ask("HHH"),ask("CCC");
        if(res[n]!='?'){
            string tmp;
            for(int i=1;i<=n;i++){
                if(res[i]!='?')tmp+=res[i];
                else tmp+='O';
            }
            return tmp;
        }
        ask("OOCC");
        if(res[1]!='?'){
            return "OOCC";
        }
        return "OOHH";
    }
    int now=0;
    for(int i=n;i>=1;i--){
        if(res[i]!='?'){
            now=i;
            break;
        }
    }
    for(int i=now-2;i>=1;i--){
        if(res[i]=='?'){
            for(int j=0;j<3;j++){
                if(res[i]=='?'&&!check(ch[j],res[i+1])){
                    string tmp;tmp+=ch[j];
                    for(int k=i+1;k<=now;k++)tmp+=res[k];
                    ask(tmp);
                    if(res[i]=='?'){
                        for(int k=0;k<3;k++){
                            if(k!=j&&!check(ch[k],res[i+1])){
                                res[i]=ch[k];
                            }
                        }
                    }
                }
            }
        }
    }
    while(now<n&&res[now]=='O'){
        string tmp;
        for(int i=1;i<=now;i++)tmp+=res[i];
        ask(tmp+'O');
        if(res[now+1]=='?'){
            ask(tmp+'C');
        }
        if(res[now+1]=='?'){
            res[now+1]='H';
        }
        now++;
    }
    if(now<n){
        for(int i=now+1;i<=n;i++)res[i]=res[now];
    }
    string tmp;
    for(int i=1;i<=n;i++){
        tmp+=res[i];
    }
    return tmp;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--){
        cin>>n;res.clear(),res.resize(n+5);
        string o=solve();
        cout<<"!"<<" "<<o<<endl;
        int ok;cin>>ok;
        assert(ok);
    }
}

你可能感兴趣的:(学习,c语言,开发语言)