题解 - C F 1365 G \mathrm{CF1365G} CF1365G
题目意思
S o l \mathrm{Sol} Sol
- 很巧妙的一道思维题
我们首先考虑如果可以交互的次数较多怎么做?
我们可以设 f i , j f_{i,j} fi,j 表示对于 a k a_{k} ak 的或和,其中 k k k 的第 i i i 位为 j j j。那么统计答案时候比如 P 6 = f 3 , 0 ∣ f 2 , 0 ∣ f 1 , 1 P_6=f_{3,0}|f_{2,0}|f_{1,1} P6=f3,0∣f2,0∣f1,1,因为 ( 6 ) 2 = [ 1 , 1 , 0 ] (6)_{2}=[1,1,0] (6)2=[1,1,0]
这样的做法交互次数肯定大于 13 13 13 次,我们考虑如何优化。一个方法就是把每个数的下标用二进制位表示,因为 n ≤ 1 0 3 n\leq 10^3 n≤103,并且 C 13 6 > 1 0 3 C_{13}^{6}>10^3 C136>103 所以我们对于 13 13 13 个二进制位以及 6 6 6 个 1 1 1 就足够表示所有下标了。
我们这次不再对下标进行dp,而是对其二进制编号我们用 v i v_i vi 记录,其实 v i = f i , 0 v_i=f_{i,0} vi=fi,0。那么此时我们计算 P x = ∑ v i P_x=\sum v_i Px=∑vi 其中 i i i 为 x x x 的二进制为 1 1 1 的位置。
C o d e \mathrm{Code} Code
int n,m,A[2005],t[15];
vector<int> vec[15];
inline int query(int x)
{
if(!vec[x].size()) return 0;
cout<<"?"<<" "<<(int)vec[x].size()<<" ";
For(i,0,(int)vec[x].size()-1) cout<<vec[x][i]<<" ";
cout<<endl;
cin>>m;
return m;
}
signed main()
{
io.read(n);
int S=(1ll<<13)-1;
For(i,0,S) if(__builtin_popcount(i)==6)
{
A[++*A]=i;
For(j,0,12) if(!(i&(1ll<<j))) vec[j].pb(*A);
if((*A)==n) break;
}
For(i,0,12) t[i]=query(i);
cout<<"!"<<" ";
For(i,1,n)
{
int sum=0,x=A[i];
For(j,0,12) if((x>>j)&1ll) sum|=t[j];
io.write(sum),putchar(' ');
}
return 0;
}