【數學思維】codeforces1117E Decypher the String

E. Decypher the String
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
This is an interactive problem. Remember to flush your output while communicating with the testing program. You may use fflush(stdout) in C++, system.out.flush() in Java, stdout.flush() in Python or flush(output) in Pascal to flush the output. If you use some other programming language, consult its documentation. You may also refer to the guide on interactive problems: https://codeforces.com/blog/entry/45307.

You are given a string t consisting of n lowercase Latin letters. This string was cyphered as follows: initially, the jury had a string s consisting of n lowercase Latin letters. Then they applied a sequence of no more than n (possibly zero) operations. i-th operation is denoted by two integers ai and bi (1≤ai,bi≤n), and means swapping two elements of the string with indices ai and bi. All operations were done in the order they were placed in the sequence. For example, if s is xyz and 2 following operations are performed: a1=1,b1=2; a2=2,b2=3, then after the first operation the current string is yxz, and after the second operation the current string is yzx, so t is yzx.

You are asked to restore the original string s. Unfortunately, you have no information about the operations used in the algorithm (you don’t even know if there were any operations in the sequence). But you may run the same sequence of operations on any string you want, provided that it contains only lowercase Latin letters and its length is n, and get the resulting string after those operations.

Can you guess the original string s asking the testing system to run the sequence of swaps no more than 3 times?

The string s and the sequence of swaps are fixed in each test; the interactor doesn’t try to adapt the test to your solution.

Input
Initially the testing system sends one string t, consisting of lowercase Latin letters (1≤|t|=n≤104).

Output
To give the answer, your program should print one line ! s with a line break in the end. After that, it should flush the output and terminate gracefully.

Interaction
Before giving the answer, you may submit no more than 3 queries. To ask a query, print one line in the following format: ? s′, where s′ should be a string consisting of exaclty n lowercase Latin letters. The line should be ended with a line break character. After submitting a query, flush the output and read the answer to your query — a string t′ consisting of n lowercase Latin letters, which is the result of applying the sequence of swaps to string s′. This string will be given on a separate line ended by a line break character.

If you submit an incorrect query (or ask more than 3 queries), the answer to it will be one string 0. After receiving such an answer, your program should terminate immediately — otherwise you may receive verdict “Runtime error”, “Time limit exceeded” or some other verdict instead of “Wrong answer”.


 KSJ曾經考過我們一個小小的腦筋急轉彎。1000瓶酒中有1瓶是毒藥,問:最少需要多少隻小白鼠才能把毒藥檢測出來?有的人想出了30只:把1000瓶酒三維101010擺放,十隻確定層,十隻確定行,十隻確定列。實際上運用了進制思想,當然最好的方法是採用二進制,兩隻確定毒藥的末位,兩隻確定毒藥的第二位……,總共20只就可以了(三進制有可能更優,但在1000數字下,三進制需要21只,而更大的進制明顯不會更優,另外,進制組合的方式也是有可能更優的,比如個位二進制十位三進制之類的,但經過枚舉,在1000數字下也達不到更優)
 說遠了,看看本題。相似之處就是這種進制定位法,26^3>10000,所以,我們可以用三個小寫字符爲下標編碼,每個下標必然可以得到唯一的一個三位編碼值。如果下標pos的26進制下的值是(XYZ)那麼,第一個詢問字符串中pos位置爲X+‘a’,第二個是Y+‘a’,第三個是Z+‘a’,找到這三個字母變化後的可能位置集合,取交集,則交集必然有且只有唯一元素,也就是pos變換之後所在的位置(如果有兩個元素的話,和我們的編碼唯一性質是相互矛盾的)
 這題昨天沒有現場寫出來,相當遺憾了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;

int m0=26,m1=26*26,m2=26*26*26,pos,n,p,q,r;
char s[10005],a[10005],b[10005],ans[10005];
vector<int> V1[26],V2[26],V3[26];
int bo[10005];  //bo用來求三個集合的交

int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	for(int i=0;i<n;i+=m1)
		for(int j=1;j<=m1&&j+i<=n;j++)
			a[i+j]=i/m1+'a';
	printf("? ");
	puts(a+1);
	fflush(stdout);
	scanf("%s",b+1);
	for(int i=1;i<=n;i++)
		V1[b[i]-'a'].push_back(i);
		
	for(int i=0;i<n;i+=m0)
		for(int j=1;j<=m0&&j+i<=n;j++)
			a[i+j]=(i/m0)%m0+'a';
	printf("? ");
	puts(a+1);
	fflush(stdout);
	scanf("%s",b+1);
	for(int i=1;i<=n;i++)
		V2[b[i]-'a'].push_back(i);
		
	for(int i=0;i<n;i++)
		for(int j=1;j<=1&&j+i<=n;j++)
			a[i+j]=i%m0+'a';
	printf("? ");
	puts(a+1);
	fflush(stdout);
	scanf("%s",b+1);
	for(int i=1;i<=n;i++)
		V3[b[i]-'a'].push_back(i);
		
	for(int i=0;i<n;i++)
	{
		p=i/m1;
		q=i%m1/m0;
		r=i%m0;
		for(int j:V1[p])
			bo[j]++;
		for(int j:V2[q])
			bo[j]++;
		for(int j:V3[r])
		{
			bo[j]++;
			if(bo[j]==3)
				ans[i]=s[j];
		}
		for(int j:V1[p])
			bo[j]--;
		for(int j:V2[q])
			bo[j]--;
		for(int j:V3[r])
			bo[j]--;
	}
	printf("! ");
	puts(ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章