P3540 [POI2012] SQU-Squarks

P3540 [POI2012] SQU-Squarks

题目描述

\(N\) 个数,给出一个序列 \(X_N\) 表示每两个数的和。求排序去重后这 \(N\) 个数所有可能的情况。

思路

我们设原数从小到大排序后为序列 \(a_N\)
首先想到最暴力的方法:枚举全排列,期望得分 20 分。

思考,如果我们可以通过确定某些 \(a\),就能求出整个 \(a_N\),那么就可以减少全排列的枚举次数。

我们先对 \(X_N\) 从小到大排序,那么有 \(X_1 = a_1+a_2\)\(X_2 = a_1+a_3\)。此时如果我们枚举 \(X_i = a_2+a_3\),就可以分别求出 \(a_1\)\(a_2\)\(a_3\)
当我们能够确定 \(a_1\)\(a_2\)\(a_3\) 后,考虑如何求出 \(a_4\sim a_N\)

\(X_N\) 中,如果去掉 \(X_1\)\(X_2\)\(X_i=a_2+a_3\),那么剩下的 \(X\) 中的最小值就是 \(a_1+a_4\) 的值,从而我们可以求出 \(a_4\)。推广一下我们就可以求出整个序列 \(a_N\)

因为 \(X_N\) 可能重复且需要排序,所以我们用 multiset 存储 \(X_N\)(或者写平衡树),当每次求出一个 \(a_j\) 时,判断其对于 \(X_N\) 是否合法即可。

注意枚举 \(a_2+a_3\) 的值的时候,有重复的要判掉,不然会多算重复的情况。(因为这个一直没过第一个点)

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<climits>
#include<cstdlib>
#include<vector>
#include<set>
using namespace std;
typedef long long ll;
template <typename T>
inline void read(T&x){//快读
	int w=0;x=0;
	char ch = getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') w=1;
		ch = getchar();
	}
	while(ch>='0'&&ch<='9'){
		x = (x<<1)+(x<<3)+(ch^48);
		ch = getchar();
	}
	if(w) x=-x;
}
template <typename T,typename...Args>
inline void read(T&t,Args&...args){
	read(t);read(args...);
}
const int N = 300;
int n,m,cnt;
int X[N*N];
vector < vector <int> > ans;
vector <int> a;
multiset <int> s;	
int main(){
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	read(n);m = n*(n-1)/2;
	for(int i=1;i<=m;++i) read(X[i]);
	sort(X+1,X+1+m);
	a.resize(n+1);
	for(int k=3;k<=n;++k){
		s.clear();
		if(X[k]==X[k-1]) continue;//判掉重复的情况
		a[1] = (X[1]+X[2]-X[k]) >> 1;
		a[2] = X[1]-a[1];
		a[3] = X[2]-a[1];
		if(a[1]<=0 || a[2]<=0 || a[3]<=0) continue;//都要大于零
		for(int i=3;i<=m;++i) if(i!=k) s.insert(X[i]);//不算X[k]
		int f = 0;
		for(int i=4;i<=n && !f;++i){
			a[i] = (*s.begin())-a[1];
			if(a[i]<=0) f = 1;
			for(int j=1;j<=i-1 && !f;++j){//判断a[j]是否重复
				if(s.find(a[i]+a[j])==s.end()) f=1;
				else s.erase(s.find(a[i]+a[j])); 
			}
		}
		if(f) continue;
		ans.push_back(a);//存答案
	}
	printf("%d\n",ans.size());
	for(int i=0;i<ans.size();++i){
		for(int j=1;j<=n;++j){
			printf("%d ",ans[i][j]);
		}
		putchar('\n');
	}
	// fclose(stdin);
	// fclose(stdout);
	return 0;
}

posted @ 2025-03-09 12:04  Tmbcan  阅读(18)  评论(0)    收藏  举报