1 条题解

  • 1
    @ 2026-9-19 17:27:49

    显然确定前 n−1n-1 个数后可以确定最后一个(因为是个排列),以下令 n←n−1n \gets n-1。

    考虑将序列以 L=k(k+1)2L=\dfrac{k(k+1)}{2} 为块长分块。对于每块单独进行确定该块内所有数。

    注意到对于所有 1≤k≤51 \le k \le 5,L∣nL \mid n,所以刚好可以分完,不会出现小块。

    对于每一块(设块内数字分别为 b1∼bLb_1 \sim b_L),将这个块内所有数排成三角形,如 k=4k=4 时如下:

    $$\begin{matrix} b_1 \\ b_2 & b_3 \\ b_4 & b_5 & b_6 \\ b_7 & b_8 & b_9 & b_{10} \\ \end{matrix}$$

    然后构建 kk 个询问集合 S1,S2,⋯ ,SkS_1,S_2,\cdots,S_k。

    SiS_i 包含该三角形中第 ii 行和第 ii 列的所有数,显然每个集合恰好包含 kk 个数。

    把 S1∼SkS_1 \sim S_k 给交互库询问,得到结果 T1,T2,⋯ ,TkT_1,T_2,\cdots,T_k。

    如果 xx 在 T1,T2,⋯ ,TkT_1,T_2,\cdots,T_k 中的恰好一个集合出现(记为 TpT_p),则对应三角形的第 pp 行第 pp 列的数。

    如果 xx 在 T1,T2,⋯ ,TkT_1,T_2,\cdots,T_k 中的恰好两个集合出现(记为 Tp,TqT_p,T_q),则对应三角形的第 pp 行第 qq 列的数。

    于是我们耗费了 kk 次询问得到了三角形的所有数。

    总询问次数为 2nk+1\dfrac{2n}{k+1}。刚好满足题目限制。

    #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
    上传者