CF2127G2 题解
DaiRuiChen007 · · 题解
Problem Link
单个询问几乎没有信息,考虑两个近似排列答案的变化量。
如果没有
那么加上
不妨取
那么我们如果构造
记
-
如果
n 是偶数,我们可以按如下方式构造:初始b_{d,i}=i ,\forall i\in[1,\frac n2] ,如果i-1 的第d 个二进制位是1 就交换b_i,b_{i+n/2} ,其中d\in[0,6] 。考虑任意的
(i,x,y) ,我们要求存在一个d 使得x\bmod \frac n2,y\bmod \frac n2 的第d 位相同或不同,由于\frac n2<2^{6} 所以必定存在。 -
如果
n 是奇数,我们可以按如下方式构造:b_{d,i}=(i-1)\times 2^d\bmod n+1 ,其中d\le [0,6] 。对于
(i,x,y) ,只要某个d 满足2^d(x-y)\bmod n>\frac n2 就一定能得到不同的结果,很显然。
想要知道
如果
那么我们固定
如果
因此可以在
时间复杂度
代码:
#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;
}