【随机化】【并查集】Gym - 100851J - Jump
题意:交互题,有一个长度为n(偶数)的二进制串,你需要猜不超过n+500次猜到它。如果你猜的串与原串相同的位数为n,那么会返回n,如果为n/2,那么会返回n/2,否则都会返回零。
先random,直到出现一个n/2为止,将此串视为a串。由于正态分布,肯定能在500次内查到。
然后枚举a的所有相邻元素,将相邻的元素取反后进行询问,如果返回n/2,说明相邻的这两位有一个是对的,一个是错的;如果返回不是n/2,说明这两位要么都对,要么都错。
于是用2-sat的思想,将每个元素拆点,由于是双向边,所以直接用并查集维护,同一个并查集里的全是对的/或者全是错的,最后所有元素都在两个集合中。所以最后只剩两种可能的情况了,再分别询问 一下就行了。
//fflush(stdout); #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> using namespace std; int fa[2005]; int find(int x){ return x==fa[x] ? x : fa[x]=find(fa[x]); } int n,x; char a[2005]; int Map(int x){ if(x<=n){ return x+n; } else{ return x-n; } } int main(){ srand(233); scanf("%d",&n); for(int i=1;i<=n*2;++i){ fa[i]=i; } while(1){ for(int i=1;i<=n;++i){ putchar(a[i]=((rand()&1) ? '1' : '0')); } puts(""); fflush(stdout); scanf("%d",&x); if(x==n){ return 0; } if(x==n/2){ break; } } a[n+1]='\0'; for(int i=1;i<n;++i){ a[i]=((a[i]-'0')^1)+'0'; a[i+1]=((a[i+1]-'0')^1)+'0'; puts(a+1); fflush(stdout); scanf("%d",&x); if(x==n){ return 0; } if(x==n/2){ int f1=find(i),f2=find(i+1+n); if(f1!=f2){ fa[f1]=f2; } f1=find(i+1),f2=find(i+n); if(f1!=f2){ fa[f1]=f2; } } else{ int f1=find(i),f2=find(i+1); if(f1!=f2){ fa[f1]=f2; } f1=find(i+n),f2=find(i+1+n); if(f1!=f2){ fa[f1]=f2; } } a[i]=((a[i]-'0')^1)+'0'; a[i+1]=((a[i+1]-'0')^1)+'0'; } for(int i=1;i<=n;++i){ putchar(find(i)==find(1) ? a[i] : ((a[i]-'0')^1)+'0'); } puts(""); fflush(stdout); scanf("%d",&x); if(x!=n){ for(int i=1;i<=n;++i){ putchar(find(i)==find(1+n) ? a[i] : ((a[i]-'0')^1)+'0'); } puts(""); fflush(stdout); } return 0; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/