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;
}

浙公网安备 33010602011771号