[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 }
View Code

 

posted @ 2022-02-21 21:22  PYWBKTDA  阅读(139)  评论(0编辑  收藏  举报