1 条题解
-
1
显然确定前 个数后可以确定最后一个(因为是个排列),以下令 。
考虑将序列以 为块长分块。对于每块单独进行确定该块内所有数。
注意到对于所有 ,,所以刚好可以分完,不会出现小块。
对于每一块(设块内数字分别为 ),将这个块内所有数排成三角形,如 时如下:
$$\begin{matrix} b_1 \\ b_2 & b_3 \\ b_4 & b_5 & b_6 \\ b_7 & b_8 & b_9 & b_{10} \\ \end{matrix}$$然后构建 个询问集合 。
包含该三角形中第 行和第 列的所有数,显然每个集合恰好包含 个数。
把 给交互库询问,得到结果 。
如果 在 中的恰好一个集合出现(记为 ),则对应三角形的第 行第 列的数。
如果 在 中的恰好两个集合出现(记为 ),则对应三角形的第 行第 列的数。
于是我们耗费了 次询问得到了三角形的所有数。
总询问次数为 。刚好满足题目限制。
#include<bits/stdc++.h> using namespace std; const int N=6010; int use[N],a[N],f[6][6],n,k,c,b,cc; vector<int> p[N],q; int main(){ cin>>n>>k>>c,b=k*(k+1)/2; for(int i=1;i<=(k==1?n-1:n/b);i++){ for(int x=1;x<=k;x++) for(int y=1;y<=x;y++) f[x][y]=++cc; q.clear(); for(int i=1;i<=k;i++){ vector<int> qry; for(int j=1;j<=i;j++) qry.push_back(f[i][j]); for(int j=i+1;j<=k;j++) qry.push_back(f[j][i]); cout<<"? "; for(int x:qry) cout<<x<<' '; cout<<endl; for(int j=1,x;j<=k;j++) cin>>x,q.push_back(x),p[x].push_back(i); } for(int x:q){ if(p[x].size()==1) a[f[p[x][0]][p[x][0]]]=x; else a[f[p[x][1]][p[x][0]]]=x; use[x]=1; } } for(int i=1;i<=n;i++) if(!use[i]) a[n]=i; cout<<"! "; for(int i=1;i<=n;i++) cout<<a[i]<<' '; return cout<<endl,0; }似乎可以证明这个策略是最优的。
- 1
信息
- ID
- 305
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 3
- 已通过
- 2
- 上传者