[loj6797]QC QC
性质1:若向$i$询问$j$的结果为0,则$i$和$j$中至少有一个机器故障
性质2:若$i$和$j$相互询问的结果均为1,则$i$和$j$故障状态必然相同
将$n$台机器分为若干非空等价类(同一个等价类中故障状态相同),将这些等价类分为三组:
对于第1组等价类,假设有$n_{1}$个,分别记作$S_{i}$,保证$\forall 1\le i\le n_{1},|S_{i}|=2^{k}$(其中$k$为查询轮数)
对于第2组等价类,假设有$n_{2}$对,分别记作$(X_{i},Y_{i})$,保证$\forall 1\le i\le n_{2},|X_{i}|=|Y_{i}|$且$X_{i}$和$Y_{i}$中至少有一个是故障等价类
对于第3组等价类,假设有$n_{3}$个,分别记作$T_{i}$,具体性质将在之后叙述
初始$k=0,n_{1}=n,n_{2}=n_{3}=0$且$S_{i}=\{i\}$,每轮查询如下:
每一轮操作,$\forall 1\le j\le \lfloor\frac{n_{1}}{2}\rfloor$取$x\in S_{2j-1}$和$y\in S_{2j}$并将$x$和$y$相互询问
若询问结果均为1,根据性质1将两者合并得到$S_{2j-1}\cup S_{2j}$并作为第1组等价类
否则(询问结果中存在0),根据性质2将两者合并得到$(S_{2j-1},S_{2j})$并作为第2组等价类
另外,若$2\not\mid n_{1}$则将$S_{n_{1}}$中的$n_{3}$个元素分别与某个$T_{i}$中的1个元素相互询问(可以证明$n_{3}\le 2^{k}$)
若查询结果均为1,则将$S_{n_{1}}$与$T_{i}$合并(否则不作处理),并将最终的$S_{n_{1}}$作为第3组等价类
性质3:$\forall 1\le i\le n_{3},|T_{i}|<2^{k}$且$\forall i\ne j,|T_{i}|\and |T_{j}|=0$($\and$指二进制下的与)
推论:$n_{3}\le k\le 2^{k}$
性质4:$\forall 1\le i\le n_{3},T_{i}$中至多一个等价类是非故障等价类
重复上述过程,直至$n_{1}=0$(三组等价类的性质均可归纳证明,具体过程略)
注意到第2组等价类中故障机器至少有一半,因此剩余的机器中仍有严格超过一半的非故障机器
进一步的,结合$n_{1}=0$和性质3、4,不难发现$n_{3}\ge 1$且恰仅有最大的$T_{i}$(必然唯一)是非故障等价类
另外,对最后一次操作的情况分类讨论:
1.若操作时$n_{1}=1$,那么这一轮会在第3组等价类加入$|S_{1}|=2^{k-1}$个机器
若操作前$n_{3}=0$,这一轮并不需要查询,即以$k-1$次查询得到了$2^{k-1}\ge 2^{k-2}+1$个机器的状态
若操作前$n_{3}\ge 1$,即初始$\sum_{i=1}^{n_{3}}|T_{i}|\ge 1$,进而即以$k$次查询得到了$2^{k-1}+1$个机器的状态
2.若操作时$n_{1}\ge 2$,则存在$(X_{i},Y_{i})$满足$|X_{i}|=|Y_{i}|=2^{k-1}$,同时结合性质3有$\max |T_{i}|<2^{k}$
因此$X_{i}$和$Y_{i}$不能同时是故障等价类,用最大的$T_{i}$额外查询一次,即得到了$\ge 2^{k-1}+1$个故障机器和$\ge 2^{k-1}$个非故障机器
换言之,即以$k+1$次查询得到了$\ge 2^{k}+1$个机器的状态
总得来说,设查询了$k_{0}$轮,会得到$\ge 2^{k_{0}}+1$个机器的状态和$n_{2}$对第2组等价类
设当前有$x$个非故障机器和$y$个故障机器,对其分类讨论:
1.若$x-y\le 2$,那么每一对第2组等价类均不能同时是故障等价类,因此可以一轮可以查询$x$对第2组等价类
2.若$x-y>2$,那么对每一组等价类查询,一轮可以查询$\lfloor\frac{x}{2}\rfloor$对第2组等价类
查询轮数的级别是$o(\log n)$的,并且通过具体计算必然查询必然不超过10轮
最终,总复杂度为$o(tn\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 105 4 int t,n,k,n1,n2,n3,nn1,nn3,v[N]; 5 char s[N],ans[N]; 6 vector<int>X0,Y0,S[N],X[N],Y[N],T[N],SS[N],TT[N]; 7 void query(){ 8 printf("test "); 9 for(int i=1;i<=n;i++)printf("%d ",v[i]); 10 printf("\n"); 11 fflush(stdout); 12 scanf("%s",s+1); 13 } 14 int main(){ 15 scanf("%d",&t); 16 while (t--){ 17 scanf("%d",&n); 18 k=0,n1=n,n2=n3=0; 19 for(int i=1;i<=n1;i++)S[i].clear(),S[i].push_back(i); 20 bool flag=0; 21 while (n1){ 22 if (n1==1){ 23 flag=1; 24 if (!n3){ 25 n1=0,T[++n3]=S[1]; 26 break; 27 } 28 } 29 k++,nn1=nn3=0; 30 memset(v,0,sizeof(v)); 31 for(int i=2;i<=n1;i+=2){ 32 v[S[i-1][0]]=S[i][0]; 33 v[S[i][0]]=S[i-1][0]; 34 } 35 if (n1&1){ 36 for(int i=1;i<=n3;i++){ 37 v[S[n1][i-1]]=T[i][0]; 38 v[T[i][0]]=S[n1][i-1]; 39 } 40 } 41 query(); 42 for(int i=2;i<=n1;i+=2){ 43 if ((s[S[i-1][0]]=='0')||(s[S[i][0]]=='0'))X[++n2]=S[i-1],Y[n2]=S[i]; 44 else{ 45 SS[++nn1]=S[i-1]; 46 for(int j=0;j<S[i].size();j++)SS[nn1].push_back(S[i][j]); 47 } 48 } 49 if (n1&1){ 50 for(int i=1;i<=n3;i++) 51 if ((s[S[n1][i-1]]=='0')||(s[T[i][0]]=='0'))TT[++nn3]=T[i]; 52 else{ 53 for(int j=0;j<T[i].size();j++)S[n1].push_back(T[i][j]); 54 } 55 n3=nn3,TT[++n3]=S[n1]; 56 for(int i=1;i<=n3;i++)T[i]=TT[i]; 57 } 58 n1=nn1; 59 for(int i=1;i<=n1;i++)S[i]=SS[i]; 60 } 61 X0=T[n3],Y0.clear(); 62 for(int i=1;i<n3;i++) 63 for(int j=0;j<T[i].size();j++)Y0.push_back(T[i][j]); 64 if (!flag){ 65 memset(v,0,sizeof(v)); 66 v[T[n3][0]]=X[n2][0],query(); 67 if (s[T[n3][0]]=='0')swap(X[n2],Y[n2]); 68 for(int i=0;i<X[n2].size();i++)X0.push_back(X[n2][i]); 69 for(int i=0;i<Y[n2].size();i++)Y0.push_back(Y[n2][i]); 70 n2--; 71 } 72 while (X0.size()+Y0.size()<n){ 73 int sx=X0.size(); 74 memset(v,0,sizeof(v)); 75 if (X0.size()-Y0.size()<=2){ 76 for(int i=0;i<X0.size();i++) 77 if (i<n2)v[X0[i]]=X[n2-i][0]; 78 query(); 79 for(int i=0;i<sx;i++) 80 if (n2){ 81 if (s[X0[i]]=='0')swap(X[n2],Y[n2]); 82 for(int j=0;j<X[n2].size();j++)X0.push_back(X[n2][j]); 83 for(int j=0;j<Y[n2].size();j++)Y0.push_back(Y[n2][j]); 84 n2--; 85 } 86 } 87 else{ 88 for(int i=1;i<X0.size();i+=2) 89 if ((i>>1)<n2){ 90 v[X0[i-1]]=X[n2-(i>>1)][0]; 91 v[X0[i]]=Y[n2-(i>>1)][0]; 92 } 93 query(); 94 for(int i=1;i<sx;i+=2) 95 if (n2){ 96 if (s[X0[i-1]]=='1'){ 97 for(int j=0;j<X[n2].size();j++)X0.push_back(X[n2][j]); 98 } 99 else{ 100 for(int j=0;j<X[n2].size();j++)Y0.push_back(X[n2][j]); 101 } 102 if (s[X0[i]]=='1'){ 103 for(int j=0;j<Y[n2].size();j++)X0.push_back(Y[n2][j]); 104 } 105 else{ 106 for(int j=0;j<Y[n2].size();j++)Y0.push_back(Y[n2][j]); 107 } 108 n2--; 109 } 110 } 111 } 112 for(int i=1;i<=n;i++)ans[i]='0'; 113 for(int i=0;i<X0.size();i++)ans[X0[i]]='1'; 114 printf("answer "); 115 for(int i=1;i<=n;i++)putchar(ans[i]); 116 putchar('\n'); 117 fflush(stdout); 118 } 119 return 0; 120 }