题解 CF1365G 【Secure Password】

题解 - 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,0f2,0f1,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 n103,并且 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;
}
		

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/108532179
今日推荐