• Codeforces 1286C/1287E Madhouse (交互题)


    题目链接

    C1: http://codeforces.com/contest/1286/problem/C1
    C2: http://codeforces.com/contest/1286/problem/C2

    题解

    首先考虑C1怎么做: 先询问整个串,再询问前((n-1))个字符。二者相比对,对于每一个(l=1..n), 前者都比后者多一个长度为(l)的字符串,也就是长度为(l)的后缀。求出这些后缀是什么,然后后缀之间互相比对,就可以知道每个位置的字符了。
    考虑问一遍整个串。位置(i)上的字符在整个串的长度为(l)的子串((lgt frac{n}{2}))共出现了(min(i,n-i+1,n-l+1))次。将(l)((l+1))作差,那么剩下的就是([n-l+1,l])这段区间内的字符各出现了一次。再将作差后的(l)((l-1))作差,剩下的是(l)((n-l+1))这两个字符。
    但是剩下两个字符非常难以判断。考虑用刚才的方法求出前一半,去掉前一半的影响,就可以通过差出来的字符确定答案了。
    总询问次数约(0.75n^2).
    注意特判(n=1).

    代码

    #include<bits/stdc++.h>
    #define llong long long
    using namespace std;
    
    inline int read()
    {
    	int x = 0,f = 1; char ch = getchar();
    	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
    	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
    	return x*f;
    }
    
    const int N = 101;
    const int S = 26;
    
    char str[N+3];
    
    namespace Subtask
    {
    	int a[N+3][N+3][S+3],cnta[N+3],b[N+3][N+3][S+3],cntb[N+3];
    	bool fa[N+3][N+3],fb[N+3][N+3];
    	int cur[S+3];
    	char ans[N+3];
    	void solve(int n,char ans[])
    	{
    		cout<<'?'<<' '<<1<<' '<<n-1<<' '<<endl; cout.flush();
    		for(int i=1; i<=(n-1)*n/2; i++)
    		{
    			cin>>str+1; int len = strlen(str+1);
    			cnta[len]++; for(int j=1; j<=len; j++) a[len][cnta[len]][str[j]-96]++;
    		}
    		cout<<'?'<<' '<<1<<' '<<n<<' '<<endl; cout.flush();
    		for(int i=1; i<=n*(n+1)/2; i++)
    		{
    			cin>>str+1; int len = strlen(str+1);
    			cntb[len]++; for(int j=1; j<=len; j++) b[len][cntb[len]][str[j]-96]++;
    		}
    		for(int i=1; i<=n; i++)
    		{
    			int id = 0;
    			for(int k=1; k<=cntb[i]; k++)
    			{
    				bool found = false;
    				for(int j=1; j<=cnta[i]; j++)
    				{
    					if(fa[i][j]) continue;
    					bool same = true;
    					for(int s=1; s<=S; s++) {if(a[i][j][s]!=b[i][k][s]) {same = false; break;}}
    					if(same) {found = true; fa[i][j] = true; break;}
    				}
    				if(!found) {id = k; break;}
    			}
    			for(int s=1; s<=S; s++)
    			{
    				if(b[i][id][s]!=cur[s]) {cur[s]++; ans[n-i+1] = s+96; break;}
    			}
    		}
    	}
    }
    
    int a[N+3][N+3][S+3],cnta[N+3];
    int tot[N+3][S+3];
    int dif[N+3][S+3];
    char ans[N+3];
    int n;
    
    int main()
    {
    	cin>>n;
    	if(n==1)
    	{
    		cout<<'?'<<' '<<1<<' '<<1<<endl; cout.flush();
    		cin>>ans;
    		cout<<'!'<<' '<<ans<<endl; cout.flush();
    		return 0;
    	}
    	else if(n==2)
    	{
    		Subtask::solve(2,ans);
    		cout<<'!'<<' '<<ans+1<<endl; cout.flush();
    		return 0;
    	}
    	int nn = (n+1)>>1;
    	Subtask::solve(nn,ans);
    	cout<<'?'<<' '<<1<<' '<<n<<endl; cout.flush();
    	for(int i=1; i<=n*(n+1)/2; i++)
    	{
    		cin>>str+1; int len = strlen(str+1);
    		cnta[len]++; for(int j=1; j<=len; j++) a[len][cnta[len]][j] = str[j]-96,tot[len][str[j]-96]++;
    	}
    	for(int l=nn+1; l<=n; l++)
    	{
    		for(int i=1; i<=nn; i++)
    		{
    			tot[l][ans[i]-96] -= min(i,n-l+1);
    		}
    //		printf("tot[%d]: ",l); for(int j=1; j<=S; j++) printf("%d ",tot[l][j]); puts("");
    	}
    	for(int l=nn+1; l<=n; l++)
    	{
    		for(int i=1; i<=S; i++)
    		{
    			dif[l][i] = tot[l][i]-tot[l+1][i];
    			if(dif[l][i]!=dif[l-1][i]) {ans[l] = i+96;}
    		}
    	}
    	cout<<'!'<<' '<<ans+1<<endl; cout.flush();
    	return 0;
    }
    
  • 相关阅读:
    C#在winform中操作数据库,实现数据增删改查
    未开启Hyper-V,却提示VMware Workstation与Hyper-V不兼容。
    winform实例(5)-截屏工具+保存
    winform实例(4)-播放器(wmp)
    winform实例(3)-利用摄像头进行拍照
    winform实例(2)-简单浏览器
    winform实例(1)-简单记事本
    C#异常处理
    百度文库下载破解
    学习小技能-封装字段
  • 原文地址:https://www.cnblogs.com/suncongbo/p/12165202.html
Copyright © 2020-2023  润新知