P9916 题解(2023 激励计划评分 10)
前言
Div.2 Rank
解法
从 Subtask
正解需要一个 trick:先前一个一个数的做法询问次数很多,考虑把一些数一起询问。具体地,使用二分,令
原来的集合可以用 std::vector 存储 std::pair 实现。
放代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
char ask(vector<pii> a){
vector<int> v; char c;
for(auto [l,r]:a)
for(int j=l;j<=r;j++)
v.emplace_back(j);
cout<<"? "<<v.size()<<' ';
for(int i:v)cout<<i<<' ';
cout<<endl,cin>>c;
return c;
} // 单次询问
int main(){
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--){
int n,k; cin>>n>>k>>n;
int l=1,r=n; bool f=true; char s='+';
vector<vector<pii> > a;
while(l<r){
int m=l+r+1>>1; char c;
if(f){
s='+',a={{make_pair(l,m-1)}};
c=ask(a[0]),f=false;
} // Q=0 时
else{
vector<vector<pii> > b;
for(auto i:a){
vector<pii> v=i;
v.emplace_back(l,m-1);
b.emplace_back(v);
c=ask(v);
} // 遍历并询问
a.insert(a.end(),b.begin(),b.end());
// 将产生的新集合加入 a 中
}
if(c==s)l=m; // 贡献为正,负数在右
else if(c==48)r=m-1,f=true;
else s=c,r=m-1; // 贡献为非正数,负数在左
}
cout<<"! "<<l<<endl;
}
return 0;
}