Codeforces Round #749D Omkar and the Meaning of Life (思维题,并查集)

题目大意:有一个长度为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();
}


猜你喜欢

转载自blog.csdn.net/fdxgcw/article/details/120842844