CF1286C2

Posted chasedeath

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1286C2相关的知识,希望对你有一定的参考价值。

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);
}





以上是关于CF1286C2的主要内容,如果未能解决你的问题,请参考以下文章

cf 1237 C2. Balanced Removals (Harder)

CF 949C Data Center Maintenance——思路+SCC

[CF]1526C2 Potions (Hard Version) 优先队列贪心

cf1492 C2. k-LCM (hard version)(数学+构造)

cf1012B

如何从后台弹出片段