Codeforces Round 1286C2 #612 (Div. 1) C2. Madhouse (Hard version) 解题思路 - 排列组合&字符串

Codeforces Round #612 (Div. 1) C2. Madhouse (Hard version)

This problem is different with hard version only by constraints on total answers length

It is an interactive problem

Venya joined a tour to the madhouse, in which orderlies play with patients the following game. Orderlies pick a string of length , consisting only of lowercase English letters. The player can ask two types of queries:

  • ? l r – ask to list all substrings of […]
    . Substrings will be returned in random order, and in every substring, all characters will be randomly shuffled.
  • ! s – guess the string picked by the orderlies. This query can be asked exactly once, after that the game will finish. If the string is guessed correctly, the player wins, otherwise he loses.
    The player can ask no more than 3 queries of the first type.

To make it easier for the orderlies, there is an additional limitation: the total number of returned substrings in all queries of the first type must not exceed 0.777*(+1)*(n+1).

Venya asked you to write a program, which will guess the string by interacting with the orderlies’ program and acting by the game’s rules.

Your program should immediately terminate after guessing the string using a query of the second type. In case your program guessed the string incorrectly, or it violated the game rules, it will receive verdict Wrong answer.

Note that in every test case the string is fixed beforehand and will not change during the game, which means that the interactor is not adaptive.

Input
First line contains number (1≤≤100) — the length of the picked string.

Interaction
You start the interaction by reading the number .
To ask a query about a substring from to inclusively (1≤≤≤), you should output
? l r
on a separate line. After this, all substrings of […] will be returned in random order, each substring exactly once. In every returned substring all characters will be randomly shuffled.

In the case, if you ask an incorrect query, ask more than 3 queries of the first type or there will be more than 0.777*(+1)*(n+1)
substrings returned in total, you will receive verdict Wrong answer.

To guess the string , you should output
! s
on a separate line.

After printing each query, do not forget to flush the output. Otherwise, you will get Idleness limit exceeded. To flush the output, you can use:

  • fflush(stdout) or cout.flush() in C++;
  • System.out.flush() in Java;
  • flush(output) in Pascal;
  • stdout.flush() in Python;
  • see documentation for other languages.

If you received - (dash) as an answer to any query, you need to terminate your program with exit code 0 (for example, by calling exit(0)). This means that there was an error in the interaction protocol. If you don’t terminate with exit code 0, you can receive any unsuccessful verdict.

Hack format

To hack a solution, use the following format:

The first line should contain one integer (1≤≤100) — the length of the string, and the following line should contain the string .

已知长度为n的由小写字母组成字符串,你可以输入一段区间[l,r](次数<=3),返回结果为这段区间内的所有子串(返回的一个子串可能打乱顺序),要求返回的子串个数小于0.777*(+1)*(n+1)。
输出整个字符串。

解题思路:
设一个字符串为abcdefg
[1,7]的返回结果为
a,b,c,d,e,f,g
ab,bc,cd,de,ef,fg
abc,bcd,cde,def,efg
abcd,bcde,cdef,defg
abcde,bcdef,cdefg
abcdef,bcdefg
abcdefg
可以分别看出
a(1),b(1),c(1),d(1),e(1),f(1),g(1),括号中代表出现次数
a(1),b(2),c(2),d(2),e(2),f(2),g(1),已知比上一行多了bcdef由此可以推出a,g(但是a,g无法确定先后关系)
a(1),b(2),c(3),d(3),e(3),f(2),g(1),已知比上一行多了cde由此可以推出b,f(但是b,f无法确定先后关系,此时a,g已推出)
a(1),b(2),c(3),d(4),e(3),f(2),g(1),已知比上一行多了d由此可以推出c,e,d(但是c,e无法确定先后关系,d可以确定位置,此时a,g,b,f已推出)
a(1),b(2),c(3),d(3),e(3),f(2),g(1),
a(1),b(2),c(2),d(2),e(2),f(2),g(1),
a(1),b(1),c(1),d(1),e(1),f(1),g(1),

因为前半部分的位置可以根据easy version的思路先推出abcd:https://blog.csdn.net/LU_ZHAO/article/details/104108053
然后可以确定所有位置

/// @author zhaolu

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define rep(i,a,b) for(int i=a;i
#define repe(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define clc(a,b) memset(a,b,sizeof(a))
#define INF (0x3f3f3f3f)
#define MOD (1000000007)
#define MAX (20000)
#define LEN (MAX+10)
typedef long long ll;
using namespace std;


int num[120][30];
int num2[120][30];
int num3[120][30];
int num4[120][30];
char ans[120];
char str[LEN];
int sum,len;

int main()
{
    int n,c;
    scanf("%d",&n);
    if(n==1)
    {
        printf("? 1 1\n");
        fflush(stdout);
        scanf("%s",ans);
        printf("! %s\n",ans);
        fflush(stdout);
        return 0;
    }
    else if(n==2)
    {
        printf("? 1 1\n");
        fflush(stdout);
        scanf("%s",ans);
        printf("? 2 2\n");
        fflush(stdout);
        scanf("%s",&ans[1]);
        printf("! %s\n",ans);
        fflush(stdout);
        return 0;
    }
    
    c=n;
    n=n/2;
    printf("? 1 %d\n",n);
    fflush(stdout);
    sum=n*(n+1)/2;
    while(sum--)
    {
        scanf("%s",str);
        len=(int)strlen(str);
        rep(i,0,len) ++num[len][str[i]-'a'];
    }
    if(n!=1)
    {
        printf("? 2 %d\n",n);
        fflush(stdout);
        sum=n*(n-1)/2;
        while(sum--)
        {
            scanf("%s",str);
            len=(int)strlen(str);
            rep(i,0,len) ++num2[len][str[i]-'a'];
        }
        repe(i,1,n)
        {
            rep(j,0,26)
                if(num[i][j]!=num2[i][j]) 
                    ans[i-1]='a'+j;
            rep(j,0,i) ++num2[i+1][ans[j]-'a'];
        }
    }
    else ans[0]=str[0];
    
    n=c;
    printf("? 1 %d\n",n);
    fflush(stdout);
    sum=n*(n+1)/2;
    while(sum--)
    {
        scanf("%s",str);
        len=(int)strlen(str);
        rep(i,0,len) ++num3[len][str[i]-'a'];
    }
    c=(n-1)/2;
    repe(i,1,c)
    {
        rep(j,0,26) num4[i][j]=num3[i+1][j]-num3[i][j];
    }
    repe(i,1,c)
    {
        int x=-1,y=-1;
        rep(j,0,26)
        {
            if(num3[i][j]-i*num4[i][j]!=0) 
            {
                if(x==-1) x=j;
                else y=j;
            }
        }

        if(y==-1) y=x;
        if(ans[i-1]==x+'a') ans[n-i]=y+'a';
        else ans[n-i]=x+'a';
        repe(j,i+1,c)
        {
            num3[j][x]-=i;
            num3[j][y]-=i;
        }
    }
    if(n&1)
    {
        repe(i,1,c) --num3[1][ans[i-1]-'a'],--num3[1][ans[n-i]-'a'];
        rep(i,0,26)
        {
            if(num3[1][i]==1) ans[c]='a'+i;
        }
    }
    else
    {
        int x=-1,y=-1;
        repe(i,1,c) --num3[1][ans[i-1]-'a'],--num3[1][ans[n-i]-'a'];
        rep(i,0,26)
        {
            if(num3[1][i]==2) x=y=i;
            else if(num3[1][i]==1)
            {
                if(x==-1) x=i;
                else y=i;
            }
        }
        if(ans[c]==x+'a') ans[c+1]=y+'a';
        else ans[c+1]=x+'a';
    }
    printf("! %s\n",ans);
    fflush(stdout);
    return 0;
}

你可能感兴趣的:(Codeforces,字符串,算法,数据结构,acm竞赛,程序设计)