贪心+set--luogu P3540 [POI2012]SQU-Squarks

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/83010214

传送门
贪心好题啊qwq
首先给这些和排个序,最小的那个一定是 x [ 1 ] + x [ 2 ] x[1]+x[2] ,次小的一定是 x [ 1 ] + x [ 3 ] x[1]+x[3] ,然后比 x [ 2 ] + x [ 3 ] x[2]+x[3] 小的一定是 x [ 1 ] + x [ i ] x[1]+x[i] 所以, x [ 2 ] + x [ 3 ] x[2]+x[3] 一定排在第 3 3 到第 n n 的某个位置,可以枚举

知道了 x [ 2 ] + x [ 3 ] 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 [ 2 ] + x [ 4 ] x[2]+x[4] ···以此类推,就可以将原数列全部求出

至于如何实现,用一个 m u l t i s e t 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;
}

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/83010214