专栏文章

CF2127G2 题解

CF2127G2题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minnxohy
此快照首次捕获于
2025/12/02 05:30
3 个月前
此快照最后确认于
2025/12/02 05:30
3 个月前
查看原文
单个询问几乎没有信息,考虑两个近似排列答案的变化量。
如果没有 iki\ne k 的限制,那么询问 qq 的每个循环移位答案都不变,因为原本的 qnq_n 入边贡献必定减少,出边贡献必定增多。
那么加上 iki\ne k 的限制,如果我们知道无限制时的答案,那么就能知道 qkq_k 的出边是否属于 q[k+1,n]q[k+1,n]
不妨取 k=n2+1k=\lfloor \frac n2\rfloor+1,那么每次询问 qq 就能知道每个 iiqq 中与 pip_i 的距离是否 nk\le n-k
那么我们如果构造 logn\log nqq 使得对于每个 ii,所有的 jj 每次回答不完全相同。
b=q1b=q^{-1},则对于任意 (x,y)(x,y) 存在一个 bb 使得 [bybink][bxbink][b_y-b_i\le n-k]\ne [b_x-b_i\le n-k](减法是 modn\bmod n 意义下的)。
  • 如果 nn 是偶数,我们可以按如下方式构造:初始 bd,i=ib_{d,i}=ii[1,n2]\forall i\in[1,\frac n2],如果 i1i-1 的第 dd 个二进制位是 11 就交换 bi,bi+n/2b_i,b_{i+n/2},其中 d[0,6]d\in[0,6]
    考虑任意的 (i,x,y)(i,x,y),我们要求存在一个 dd 使得 xmodn2,ymodn2x\bmod \frac n2,y\bmod \frac n2 的第 dd 位相同或不同,由于 n2<26\frac n2<2^{6} 所以必定存在。
  • 如果 nn 是奇数,我们可以按如下方式构造:bd,i=(i1)×2dmodn+1b_{d,i}=(i-1)\times 2^d\bmod n+1,其中 d[0,6]d\le [0,6]
    对于 (i,x,y)(i,x,y),只要某个 dd 满足 2d(xy)modn>n22^d(x-y)\bmod n>\frac n2 就一定能得到不同的结果,很显然。
想要知道 qq 在无限制下的答案,需要先确定任意一个 px=yp_x=y
如果 nn 是偶数,设 n=2mn=2m,则询问 [q1,,qm,qm+1,q2m][q_1,\dots,q_{m},q_{m+1},\dots q_{2m}][q2m,q2m1,,qm,qm+1,qm1,qm2q1][q_{2m},q_{2m-1},\dots,q_m,q_{m+1},q_{m-1},q_{m-2}\dots q_1],此时对于任意 iqm+1i\ne q_{m+1}ipii\to p_i 在两个排列中恰有一个产生贡献,除非 i=qm,pi=qm+1i=q_m,p_i=q_{m+1}
那么我们固定 qm+1q_{m+1},枚举 qmq_m 就能找到 px=qm+1p_x=q_{m+1}xx,具体来说找到两次询问之和 =n=n 的一个作为 xx 即可。
如果 nn 是奇数,那么固定 qn=nq_n=n,然后 qm=1n1q_m=1\sim n-1 都不满足的时候则 x=nx=n,注意此时 qm=xq_m=x 时答案之和不一定是 nn,要找和最大的一个作为 xx
因此可以在 2n2n 次操作内确定 (x,y)(x,y),然后 7n7n 次询问还原排列,总次数 2n+nlog2n2n+n\log_2n
时间复杂度 O(n2logn)\mathcal O(n^2\log n)
代码:
CPP
#include<bits/stdc++.h>
using namespace std;
int n,a[105][105],b[105],p[105],q[105],w[105];
int ask() {
	cout<<"?";
	for(int i=1;i<=n;++i) cout<<" "<<q[i];
	cout<<endl;
	int o; cin>>o; return o;
}
void solve() {
	cin>>n;
	int k=n/2+1,x=n,y=k; //find p[x]=y
	cout<<k<<endl;
	for(int i=1,m=n-(n&1),c=0;i<=m;++i) if(i!=k) {
		iota(q+1,q+n+1,1),swap(q[i],q[k-1]);
		int z=ask();
		reverse(q+1,q+m+1),swap(q[k],q[k-1]),z+=ask();
		if(i>1&&z>c) { x=i; break; }
		else if(c>z) { x=1; break; }
		else c=z;
	}
	memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
	iota(p+1,p+n+1,1);
	for(int d=0;d<7;++d) {
		if(~n&1) {
			iota(p+1,p+n+1,1);
			for(int i=1;i<=n/2;++i) if((i-1)>>d&1) swap(p[i],p[i+n/2]);
		}
		for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]|=((p[j]+n-p[i])%n<=n-k)<<d;
		for(int i=1;i<=n;++i) q[p[i]]=i;
		for(int i=1;i<=n;++i) w[q[k]]=ask(),rotate(q+1,q+2,q+n+1);
		int o=w[x]+((p[y]+n-p[x])%n<=n-k);
		for(int i=1;i<=n;++i) b[i]|=(o-w[i])<<d;
		if(n&1) for(int i=1;i<=n;++i) p[i]=(p[i]-1)*2%n+1;
	}
	for(int i=1;i<=n;++i) q[i]=find(a[i]+1,a[i]+n+1,b[i])-a[i];
	cout<<"!";
	for(int i=1;i<=n;++i) cout<<" "<<q[i];
	cout<<endl;
}
signed main() {
	int _; cin>>_;
	while(_--) solve();
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...