题目大意:有一个长度为n的无重复元素的序列A,最多可以执行2n次询问,每次询问由一个?加上一个长度为n的序列B。
spj会让AB对位相加,然后返回由新序列中最小的索引K,要求K索引所对应的值在新序列中出现不止一次,若找不到,就返回0
设n=5,可以询问例如 1 1 1 1 2 这样的数据,此时返回的数值就是比第五位数大1的那个数的位置
假设序列A是3 2 1 5 4,我们询问1 1 1 1 2,得到回复4,即4号位比5号位大1
我们询问1 1 1 2 1,得到回复 0,即4号位是最大的
询问 1 1 2 1 1,得到2,即2号位比3号位大1
询问1 2 1 1 1,得到1,即1号位比2号位大1
询问2 1 1 1 1,得到1,这个数据是没有意义的,找不到任何线索。
仅凭借上面的信息还是无法推出全部,所以可以再询问 2 2 2 2 1,得到回复1,即5号位比1号位大1
2 2 2 1 2,得到回复5,即4号位比5号位大1
就这样循环下去询问2n次,此时的线索就足以推导出结果
随后就用类并查集的方式(或者说像链式向前星)去记录位置之间的大小关系,就能得到答案
挺考验代码实现能力的,比赛的时候很快就想出了思路,但代码花了一个多小时都没写出来QWQ掉大分
交互题调试起来巨麻烦QWQ
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 110;
int n;
int ans[N];
int nxt[N];//
int pre[N];//
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cout << " ?";
for (int j = 1; j <= n; j++) {
if (j != i)
cout << " " << 1;
else
cout << " " << 2;
}
cout << endl;
int x;
cin >> x;
if (x != i && x != 0)
nxt[i] = x, pre[x] = i; //
}
for (int i = 1; i <= n; i++) {
cout << " ?";
for (int j = 1; j <= n; j++) {
if (j != i)
cout << " " << 2;
else
cout << " " << 1;
}
cout << endl;
int x;
cin >> x;
if (x != i && x != 0)
nxt[x] = i, pre[i] = x; //
}
int aim = 0;
for (int i = 1; i <= n; i++)
if (!pre[i])
aim = i;
int sum = 0;
for (int i = aim; i; i = nxt[i]) {
ans[i] = ++sum;
}
cout << "! ";
for (int i = 1; i <= n; i++) {
cout << ans[i] << " ";
}
cout << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}