题解:P17115 [Algo Beat 009 & MROI-R1] ANDOR
分享一个可以拓展到
首先可以不看
然后注意到不同二进制位直接是互不影响的,因此可以按位考虑。
当前只考虑某一位,设
因此,可以依次询问相邻的点,只要出现过前两种情况就可以确定整个序列(因为任意相邻数的关系都是确定的,确定一个数就可以顺着推出所有数)。
举个例子:
不看
那问题来了,如果没有任何点可以确定,也就是
这里给出两种方法:
方法一
虽然无法确定具体值,但是可以知道奇偶性相同的项是相同的,因此再问
总询问次数是
:::info[CODE]{close}
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,k,f[N],g[N],a[N],b[N],vis[N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<n-1;i++)
{
printf("? and %d %d\n",i,i+1);
fflush(stdout);
scanf("%d",&f[i]);
printf("? or %d %d\n",i,i+1);
fflush(stdout);
scanf("%d",&g[i]);
}
printf("? and 1 3\n");
fflush(stdout);
scanf("%d",&f[0]);
printf("? or 1 3\n");
fflush(stdout);
scanf("%d",&g[0]);
for(int i=0;i<=17;i++)
{
memset(b,-1,sizeof(b));
int flag=0;
for(int j=1;j<n-1;j++)
{
int u=(f[j]>>i)&1,v=(g[j]>>i)&1;
if(u==v)
{
flag=1;
b[j]=b[j+1]=u;
}
}
if(!flag)
b[1]=b[3]=(f[0]>>i)&1;
for(int j=2;j<n;j++)
if(b[j-1]!=-1&&b[j]==-1)
b[j]=!b[j-1];
for(int j=n-2;j>=1;j--)
if(b[j+1]!=-1&&b[j]==-1)
b[j]=!b[j+1];
for(int j=1;j<n;j++)
a[j]+=b[j]<<i;
}
for(int i=1;i<n;i++)
vis[a[i]]=1;
for(int i=0;i<n;i++)
if(!vis[i])
{
a[n]=i;
break;
}
putchar('!');
for(int i=1;i<=n;i++)
printf(" %d",a[i]);
putchar('\n');
fflush(stdout);
return 0;
}
:::
方法二
注意到,一个随机排列某一位
总询问次数是
:::info[CODE]{close}
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
int n,k,f[N],g[N],a[N],b[N],vis[N],t1[N],t2[N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++)
t1[i]=i;
shuffle(t1+1,t1+n,rnd);
for(int i=1;i<=n;i++)
t2[t1[i]]=i;
for(int i=1;i<n-1;i++)
{
printf("? and %d %d\n",min(t1[i],t1[i+1]),max(t1[i],t1[i+1]));
fflush(stdout);
scanf("%d",&f[i]);
printf("? or %d %d\n",min(t1[i],t1[i+1]),max(t1[i],t1[i+1]));
fflush(stdout);
scanf("%d",&g[i]);
}
for(int i=0;i<=17;i++)
{
memset(b,-1,sizeof(b));
for(int j=1;j<n-1;j++)
{
int u=(f[j]>>i)&1,v=(g[j]>>i)&1;
if(u==v)
b[j]=b[j+1]=u;
}
for(int j=2;j<n;j++)
if(b[j-1]!=-1&&b[j]==-1)
b[j]=!b[j-1];
for(int j=n-2;j>=1;j--)
if(b[j+1]!=-1&&b[j]==-1)
b[j]=!b[j+1];
for(int j=1;j<n;j++)
a[j]+=b[j]<<i;
}
for(int i=1;i<n;i++)
vis[a[i]]=1;
for(int i=0;i<n;i++)
if(!vis[i])
{
a[n]=i;
break;
}
putchar('!');
for(int i=1;i<n;i++)
printf(" %d",a[t2[i]]);
printf(" %d",a[n]);
putchar('\n');
fflush(stdout);
return 0;
}
:::