CF2037E 题解
不错的题。
首先,不能这么做:
-
尝试把原来的序列分成若干个小序列。
-
尝试对小序列进行大分讨。
这样做的不足之处:
-
分类讨论情况太多了,询问次数会超。
-
断成若干个小序列,等于忽略了不同序列之间的条件,导致答案错误。
我们发现最多询问
可以发现如果
- 由于
f(1,i + 1)\ne 0 ,所以[1,i] 中一定存在0 。 - 由于
f(1,i)=0 ,那么这一段一定没有任何一个0 在1 的前面。
综上,我们可以得出:此时
那么后缀的
之后该怎么办呢?注意到另一件事,就是左端点不动,右端点单增时,答案不可能变小,那么我们找到第一个满足上述条件的位置
-
如果
f(1,j)=f(1,j-1) ,那么说明j 这个位置一定无法和前面配对,由于我们的i 符合刚才说的条件,那么此时j 前面一定有0 存在,如果它没有配成,说明这个位置一定是0 (要是是1 一定可以和前面的0 做出贡献)。 -
反之则为
1 。
那么我们直接再扫一遍就可以了。
什么时候没有唯一解呢?就是没有找到
代码:
#include <bits/stdc++.h>
#define f(i ,m ,n ,x) for (int i = (m) ; i <= (n) ; i += (x))
using std :: cin ; using std :: cout ; using std :: endl ;
int t ,n ,ch[10007] ;
int main () {
cin >> t ;
while (t --) {
cin >> n ;
int ans = 0 ; bool flag (0) ;
cout << "? " << 1 << ' ' << 2 << endl ;
cin >> ans ;
if (ans == 1) { ch[1] = 0 , ch[2] = 1 ,flag = true ;}
f (i ,3 ,n ,1) {
cout << "? " << 1 << ' ' << i << endl ;
int res ; cin >> res ;
if (flag == false) {
if (res ^ 0) {
f (j ,1 ,i - 1 - res ,1) ch[j] = 1 ;
f (j ,i - res ,i - 1 ,1) ch[j] = 0 ;
ch[i] = 1 , flag = true ;
}
ans = res ;
} else {
if (res == ans) ch[i] = 0 ;
else ch[i] = 1 ;
ans = res ;
}
}
if (ans == 0) cout << "! IMPOSSIBLE" << endl ;
else {
cout << "! " ;
f (i ,1 ,n ,1) cout << ch[i] ; cout << endl ;
}
}
return 0 ;
}