题解:CF2129C3 Interactive RBS (Hard Version)
做法
一个比较劣的做法。
首先可以先二分出来一个右括号,右括号可以用来分割两端,后面有用。具体的二分方法就是,查询原串的一个后缀,找到最后一个不为 ())))))...((((,因为为 ))))(((( 这种。这样就找到了一个右括号。二分最多花费
然后考虑构造一种方法能查询一个集合中有几个左括号。最简单的构造是 i1))i2))i3))i4)),这样每个位置都互不干扰。有了这个操作如何得出答案呢?考虑放 i1))i2))i2))i3))i3))i3))i3))...,这样可以用一个长度为
分割用的右括号其实是多余的,考虑直接查询 i1 i2 i2 i3 i3 i3 i3... 这种,再在最后放
发现我们每次询问的长度只有 a)a)a)a)...,如果
做完之后才发现二进制完全被平方吊打了,其实全部使用平方即可。
代码
#include<bits/stdc++.h>
#define int long long
#define ll long long
#define ull unsigned long long
#define pii pair<ll,ll>
#define fi first
#define se second
#define i128 __int128
#define ALL(x) x.begin(),x.end()
#define popcount(x) __builtin_popcountll(x)
#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) 42
#endif
using namespace std;
const int INF=1e18;
const int N=100005;
const int MOD1=1e9+7,MOD2=998244353;
const int MOD=MOD1;
int query(vector<int> vec){
cout<<"? ";
cout<<vec.size()<<" ";
for(auto i:vec){
cout<<i<<" ";
}
cout<<"\n";
cout.flush();
int x;
cin>>x;
//debug(x);
return x;
}
int ans[1005];
void solve_(){
//二分出一个右括号
int n;
cin>>n;
//找到最后一个不为0的位置
int l=1,r=n,res=0;
while(l<=r){
int mid=(l+r)/2;
vector<int> tmp;
for(int i=mid;i<=n;i++){
tmp.push_back(i);
}
if(query(tmp)>0){
res=mid;
l=mid+1;
}else{
r=mid-1;
}
}
int pos=res+1;
//debug(ANS,pos);
for(int l=1;l<=n;l+=12){
int r=min(n,l+11);
vector<int> tmp;
for(int i=l;i<=min(r,l+7);i++){
//前8个
for(int j=0;j<(1<<(i-l));j++){
tmp.push_back(i);
}
}
int x=tmp.size()+1;
for(int i=0;i<x;i++){
tmp.push_back(pos);
}
//后5个:平方
//23*24/2=276
if(l+8<=r){
for(int i=0;i<23;i++){
tmp.push_back(l+8);
tmp.push_back(pos);
}
}
tmp.push_back(pos);
//33*34/2=561
if(l+9<=r){
for(int i=0;i<33;i++){
tmp.push_back(l+9);
tmp.push_back(pos);
}
}
tmp.push_back(pos);
//47*48/2=1128
if(l+10<=r){
for(int i=0;i<47;i++){
tmp.push_back(l+10);
tmp.push_back(pos);
}
}
tmp.push_back(pos);
//67*68/2=2278
if(l+11<=r){
for(int i=0;i<67;i++){
tmp.push_back(l+11);
tmp.push_back(pos);
}
}
int res=query(tmp);
if(res>=2278){
res-=2278;
ans[l+11]=0;
}else{
ans[l+11]=1;
}
if(res>=1128){
res-=1128;
ans[l+10]=0;
}else{
ans[l+10]=1;
}
if(res>=561){
res-=561;
ans[l+9]=0;
}else{
ans[l+9]=1;
}
if(res>=276){
res-=276;
ans[l+8]=0;
}else{
ans[l+8]=1;
}
for(int i=0;i<=7;i++){
if(l+i<=r){
if((res>>i)&1){
ans[l+i]=0;
}else{
ans[l+i]=1;
}
}
}
}
cout<<"! ";
for(int i=1;i<=n;i++){
cout<<(ans[i]==0?'(':')');
}
cout<<"\n";
cout.flush();
}
signed main(){
int testcase,multitest=1;
if(multitest)cin>>testcase;
else testcase=1;
while(testcase--){
solve_();
}
return 0;
}