CF1286C2 - Madhouse (Hard version)

CF1286C2 - Madhouse (Hard version)

题目大意

交互器生成了一个串\(s\),可以用3次操作,每次

? l r 询问\([l,r]\)内所有连续子串,

交互器返回所有连续子串随机排列(字符位置和串的顺序均随机)的结果

额外要求:查询的总子串个数$\leq \lceil 0.777 (n+1)^2 \rceil $

最后 ! s 输出答案


分析

看一看\(0.777\approx \cfrac{7}{9}\)

于是乎我就写了一个0.75的做法?

由于思路顺序极为奇怪,所以实现方法也很奇怪

从长到短确定

从\(L=n,n-1,\cdots 1\)依次确定每一种长度的每一个串对应的字符集

假设当前知道\(L+1\)层的样子,可以通过相邻取交确定下一层除了第一个和最后一个的所有串

将他们删掉后,就知道当前头尾字符\(s[n-L+1],s[L]\)是什么

再确定头字符即可

确定头字符

考虑对于一个串,可以用以下方法两次求出整串

1.查询整串\([1,n]\)得到集合\(S\)

2.查询\([2,n]\)得到集合\(T\)

计算\(S-T\),即得到所有\([1,i]\)串的字符集,依次作差即可

用这个确定前半个串,消耗\((\frac{n}{2})^2\)

结合前面的即可

代码实现比较奇怪



const int N=110,INF=1e9+10;

int n;
struct Node{
	int c[26],n;
	Node(){ memset(c,n=0,sizeof c); }
	Node operator & (const Node __) const {
		Node res;
		rep(i,0,25) res.n+=res.c[i]=min(c[i],__.c[i]);
		return res;
	}
	int operator < (const Node __) const {
		if(n!=__.n) return n<__.n;
		rep(i,0,25) if(c[i]!=__.c[i]) return c[i]<__.c[i];
		return 0;
	}
	int operator == (const Node __) const {
		rep(i,0,25) if(c[i]!=__.c[i]) return 0;
		return 1;
	}
	char operator - (const Node __) const {
		rep(i,0,25) if(c[i]>__.c[i]) return i+'a';
		return -1;
	}
	void Show(){
		cout<<"L="<<n<<' '; rep(i,0,25) rep(j,1,c[i]) putchar(i+'a');
		puts("");
	}
};
Node Read(){
	static char s[N];
	scanf("%s",s);
	Node t;
	for(int i=0;s[i];++i) t.n++,t.c[s[i]-'a']++;
	return t;
}

char s[N];
void Sub1(){
	int m=(n+1)/2;
	multiset <Node> st;
	printf("? %d %d\n",1,m),fflush(stdout);
	rep(i,1,m*(m+1)/2) st.insert(Read());
	if(m>1) {
		printf("? %d %d\n",2,m),fflush(stdout);
		rep(i,1,m*(m-1)/2) st.erase(st.find(Read()));
	}
	Node lst;
	int p=0;
	for(Node i:st) s[++p]=i-lst,lst=i;
}

multiset <Node> st[N];
Node A[N][N];

void Sub2(){
	printf("? %d %d\n",1,n),fflush(stdout);
	rep(i,1,n*(n+1)/2) {
		Node t=Read();
		if(t.n==n) A[1][1]=t;
		else st[t.n].insert(t);
	}
	//rep(i,1,n) {
		//puts("---");
		//for(auto j:st[i]) j.Show();
	//}
	rep(i,1,n/2) {
		//cout<<"$"<<i<<' '<<s[i]<<endl;
		//rep(j,1,i) A[i][j].Show();
		rep(j,1,i-1) {
			A[i][j].c[s[j]-'a']--,A[i][j].n--;
			A[i+1][j+1]=A[i][j];
			//cout<<"Erase: "; A[i+1][j+1].Show();
			//for(auto t:st[n-i]) t.Show();
			assert(st[n-i].find(A[i+1][j+1])!=st[n-i].end());
			st[n-i].erase(st[n-i].find(A[i+1][j+1]));
			A[i][j].c[s[j]-'a']++,A[i][j].n++;
		}
		Node a=*st[n-i].begin();
		Node b=*st[n-i].rbegin();
		Node x=A[i][1],y=A[i][i];
		y.c[s[i]-'a']--;
		s[n-i+1]=x-(a==y?b:a);
		if(a==y) A[i+1][1]=b,A[i+1][i+1]=a;
		else A[i+1][1]=a,A[i+1][i+1]=b;
		//cout<<s[n-i+1]<<endl;
	}
}

int main(){
	n=rd();
	Sub1(),Sub2();
	printf("! ");
	s[n+1]=0,puts(s+1);
	fflush(stdout);
}





上一篇:github rep


下一篇:2021-06-02