CF1896G Pepe Racing 题解
KobeBeanBryantCox · · 题解
CF1896G Pepe Racing 题解
题目传送门。
被 Idleness limit exceeded 卡了一小时发现是少了一个 for 循环。。。
这个题细节很多,注意仔细看代码,好好推敲。
题意
交互题,有
解法
注意到
考虑一个一个找,每次找到一个最大值就把它从集合里删掉,再进行重复操作。
考虑给
找一次全局最大值,只需要在每组询问一个块内最大值,再把这些块内最大值放在一起询问全局最大值。
显然多次这样做不合理。考虑优化寻找的方法。
注意到每次找到一个最大值,就要删去它。而删去它只会改变一个块的最大值。
那我们只需要查询被改变的块的块内最大值,再查询一次全局最大值。
但是现在删去了一个数,块内不到
分析查询次数。预处理每块最大值和第一次的全局最大值要
还多了
考虑只剩下
由于还是分成了
为什么我们已经确定了
然后对于
分析查询次数:
详见代码,注释清楚。
AC 代码
注意下面代码:所有数组存的都是下标。
#include<bits/stdc++.h>
#define Code using
#define by namespace
#define wjb std
Code by wjb;
const int N=410;
int ask(set<int> &s) // 询问区间最大值
{
cout<<"? ";
for(auto a:s)cout<<a<<" ";
cout<<"\n",fflush(stdout); // 清空缓冲区!!!
int x;
cin>>x;
return x;
}
bool vis[N]; // 记录出现过的块内最大值
int n;
void get(set<int> &s) // 补充块
{
int num=1;
while(s.size()<n) // 补到 n
{
while(vis[num]||s.find(num)!=s.end())num++; // 不能是其他块的块内最大值
s.insert(num);
}
}
int maxx[N]; // 块内最大值
set<int>a[N]; // 元素
vector<int>ans; // 答案数组
void solve()
{
cin>>n;
for(int i=0;i<=n*n+1;i++)vis[i]=false,maxx[i]=0,a[i].clear(); // 多测不清空,爆零两行泪
ans.clear();
for(int i=1;i<=n;i++)
{
for(int j=(i-1)*n+1;j<=i*n;j++)a[i].insert(j); // 初始化元素
maxx[i]=ask(a[i]),vis[maxx[i]]=true; // 查询块内最大值
}
for(int _=n*n;_>=2*n;_--) // 2n-1 之前的操作
{
set<int>now;
for(int i=1;i<=n;i++)now.insert(maxx[i]); // 把块内最大值放进一个 set
get(now); // 补充少的元素
int x=ask(now),id=0; // 查询全局最大值
for(int i=1;i<=n;i++)
if(maxx[i]==x)id=i; // 记录全局最大值出现的块编号
ans.push_back(x); // 计入答案
a[id].erase(x),get(a[id]); // 删去全局最大值并补充
maxx[id]=ask(a[id]),vis[maxx[id]]=true; // 因为修改(有删除)了,所以重新查询块内最大值
for(int i=1;i<=n;i++)
if(i!=id)a[i].erase(maxx[id]); // 由于之前补入的是其他块内的元素,所以有可能存在相同,要删去,我就是这里少了,卡了 1 小时
}
set<int>now;
for(int i=1;i<=n;i++)now.insert(maxx[i]); // 直接把块内最大值放进 set
get(now);
for(int _=n-1;_;_--) // 注意是 n-1
{
int x=ask(now); // 查询最大值
now.erase(x),get(now),ans.push_back(x); // 删除、补入、计入答案的常规操作
}
for(int x:now)
if(vis[x])ans.push_back(x); // 把最后一个补进来,由于块内最大值是之前被 vis 记录过的,所以可以用 vis 来补
cout<<"! ";
for(int a:ans)cout<<a<<" ";
cout<<"\n",fflush(stdout); // 输出答案,注意要清空缓冲区!!!
}
int main()
{
int t;
cin>>t;
while(t--)solve();
return 0;
}
后记
注意事项:
多测不清空,爆零两行泪!
如果有讲错的地方,欢迎提出修正;如果有讲得不清楚的地方,欢迎提问。
给个赞吧,给个关注吧 QWQ~