传送门
贪心好题啊qwq
首先给这些和排个序,最小的那个一定是
x
[
1
]
+
x
[
2
]
x[1]+x[2]
x[1]+x[2],次小的一定是
x
[
1
]
+
x
[
3
]
x[1]+x[3]
x[1]+x[3],然后比
x
[
2
]
+
x
[
3
]
x[2]+x[3]
x[2]+x[3]小的一定是
x
[
1
]
+
x
[
i
]
x[1]+x[i]
x[1]+x[i]所以,
x
[
2
]
+
x
[
3
]
x[2]+x[3]
x[2]+x[3]一定排在第
3
3
3到第
n
n
n的某个位置,可以枚举
知道了 x [ 2 ] + x [ 3 ] x[2]+x[3] x[2]+x[3]就可以知道 x [ 1 ] x [ 2 ] x [ 3 ] x[1]\ x[2]\ x[3] x[1] x[2] x[3]分别是多少,剩下的数中 x [ 1 ] + x [ 4 ] x[1]+x[4] x[1]+x[4]一定是最小的,然后我们也可以知道 x [ 2 ] + x [ 4 ] x[2]+x[4] x[2]+x[4]···以此类推,就可以将原数列全部求出
至于如何实现,用一个 m u l t i s e t multiset multiset就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#define maxn 90000
#define LL long long
using namespace std;
int n,a[maxn],tot,ans[305],res[305][305],cnt;
multiset<int> s;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void solve(int sum){
s.clear();
for(int i=1;i<=tot;i++) s.insert(a[i]);
if((a[1]+a[2]+sum)&1) return;
ans[1]=(a[1]+a[2]-sum)>>1;
ans[2]=(a[1]+sum-a[2])>>1;
ans[3]=(a[2]+sum-a[1])>>1;
if(ans[1]<0 || ans[2]<0 || ans[3]<0) return;
s.erase(s.find(ans[1]+ans[2]));
s.erase(s.find(ans[2]+ans[3]));
s.erase(s.find(ans[1]+ans[3]));
for(int i=4;i<=n;i++){
ans[i]=*s.begin()-ans[1];
if(ans[i]<0) return;
for(int j=1;j<i;j++){
int tmp=ans[j]+ans[i];
if(s.find(tmp)==s.end()) return;
s.erase(s.find(tmp));
}
}
for(int i=2;i<=n;i++)
if(ans[i]<=ans[i-1])
return;
cnt++;
for(int i=1;i<=n;i++)
res[cnt][i]=ans[i];
}
int main(){
n=rd(); tot=n*(n-1)>>1;
for(int i=1;i<=tot;i++) a[i]=rd();
sort(a+1,a+tot+1);
for(int i=3;i<=n;i++)
if(i==3 || a[i]!=a[i-1])
solve(a[i]);
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++){
for(int j=1;j<=n;j++) printf("%d ",res[i][j]);
printf("\n");
}
return 0;
}