题解:CF2156D Find the Last Number
喜提
8 个 WA!
我们很显然有一个
然后仔细观察,发现可以用一种神奇的方法给等式右边同时减去那些
这里
然后你就会发现,这个东西的询问次数其实是:
虽然这玩意看似在
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4+5;
const int mx = 2e4;
int a[N];
int b[N];
int bx[N];
int by[N];
int P[N];
int hou[N];
int dian[N];
int NP[N][2];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
for(int i = 1;i<=mx;++i)
{
int s = (i&1);
b[i] = b[i-1]+s;
bx[i] = bx[i-1];
by[i] = by[i-1];
if(s)
{
bx[i]+=((i&2)>0);
}
else
{
by[i]+=((i&2)>0);
}
}
int _;
cin >> _;
while(_--)
{
int n;
cin >> n;
int cnt = 0,numx = 0;
for(int i = 1;i<n;++i)
{
cout << "? " << i << " 1" << endl;
cin >> dian[i];
cnt+=dian[i];
}
int w = b[n]-cnt;
hou[0] = w;
for(int i = 1;i<n;++i)
{
if(dian[i] == w)
{
P[++numx] = i;
}
}
int ans = w;
int s = 31-__builtin_clz(n);
int num1 = 0,num2 = (w == 0?by[n]:bx[n]);
int nx = 0,ny = 0;
for(int i = 1;i<=numx;++i)
{
cout << "? " << P[i] << " 2" << endl;
int x;
cin >> x;
num1+=(x>0);
if(!x)
{
NP[++nx][0] = P[i];
}
else
{
NP[++ny][1] = P[i];
}
}
for(int i = 1;i<=s;++i)
{
ans+=(1<<i)*(num2-num1);
if(i == s)
{
continue;
}
w = num2-num1;
hou[i] = w;
for(int j = 1;j<=(w?ny:nx);++j)
{
P[j] = NP[j][w];
}
numx = (w?ny:nx);
nx = 0,ny = 0;
num1 = 0;
for(int j = 1;j<=numx;++j)
{
cout << "? " << P[j] << ' ' << (1<<i+1) << endl;
int x;
cin >> x;
num1+=(x>0);
if(!x)
{
NP[++nx][0] = P[j];
}
else
{
NP[++ny][1] = P[j];
}
}
num2 = 0;
for(int j = 1;j<=n;++j)
{
int dui = 1;
for(int k = 0;k<=i;++k)
{
int flag = ((j&(1<<k))>0);
if(flag!=hou[k])
{
dui = 0;
break;
}
}
if(dui)
{
num2+=((j&(1<<i+1))>0);
}
}
}
cout << "! " << ans << endl;
}
return 0;
}