BZOJ2797. [Poi2012]Squarks

Description


设有n个互不相同的正整数{X1,X2,...Xn},任取两个Xi,Xj(i≠j),能算出Xi+Xj。
现在所有取法共n*(n-1)/2个和,要你求出X1,X2,...Xn。

 

Input

第一行一个正整数n (3<=n<=300)。
第二行n*(n-1)/2个正整数(每个正整数不超过10^8),表示任取两个Xi,Xj(i≠j)算出的n*(n-1)/2个和。

 

Output

第一行一个正整数k,表示方案数。测试数据保证至少存在一种方案。
下面k行每行给出递增的n个正整数。方案按照{Xi}的最小值从大到小输出。

 

Sample Input

Sample Input 1
4
3 5 4 7 6 5


Sample Input 2
4
11 17 12 20 21 15

Sample Output

Sample Output 2
2
4 7 8 13
3 8 9 12

Sample Output 1
1
1 2 3 4

    令a1<a2<a3<......显然给定的数组中最小的是a1+a2,次小的是a1+a3,那么根据一些基础的线性代数知识,我们只要枚举a2+a3,这样我们就可以得到a1,a2,a3。现在考虑知道了a1,a2...ak,那么现在我们已经有了(k+1)*k/2个和,我们考虑剩下的数中,最小的一定是a1+a_k+1,那么我们就知道了a_k+1,multiset实现(你要想写平衡树我不拦你)即可。

    比较难过的是此题需要一定的卡常。(同样的算法,neither_nor大爷过了,我T了,坑爹啊

#include<bits/stdc++.h>
using namespace std;
const int N=305;
int ans[N][N],b[N*(N-1)/2+2],cnt=0,m,n,a[N],pd=0;
inline int read(){
    int x=0,f=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
multiset<int> s;
inline void solve(int p){
    if (pd==0) s.clear();
    for (register int i=3;i<=m;i++){
        if (i==p) continue;
        s.insert(b[i]);
    }
    multiset<int>::iterator it;
    for (register int i=4;i<=n;i++){
        int q=*s.begin();
        a[i]=q-a[1];
        if (a[i]<=a[i-1]) { pd=0;
        return;}
        for (register int j=1;j<i;j++){
            it=s.find(a[i]+a[j]);
            if (*it!=a[i]+a[j]){pd=0; return;}
            s.erase(it);
        }
    }
    cnt++;
    for (register int i=1;i<=n;i++)
    ans[cnt][i]=a[i];
    pd=1;
}
int main(){
    n=read();
    m=n*(n-1)/2;
    for (register int i=1;i<=m;i++) b[i]=read();
    sort(b+1,b+1+m);
    for (register int i=3;i<=m;i++){
        if (i>3&&(b[i]==b[i-1])) continue;
        int t=b[i]; 
        if ((t-b[2]+b[1])%2==1) continue;
        a[2]=(t-b[2]+b[1])/2;
        a[1]=b[1]-a[2];
        a[3]=t-a[2];
        if (a[1]<0||a[2]<0||a[3]<0) continue;
        if (a[2]<=a[1]||a[2]>=a[3]||a[1]>=a[3]) continue;
        solve(i);
    }
    printf("%d\n",cnt);
    for (register int k=1;k<=cnt;k++){
        for (register int i=1;i<=n;i++) printf("%d ",ans[k][i]);
        printf("\n");
    }
    return 0;
}
View Code

 

posted @ 2020-10-27 16:28  Cardinal  阅读(74)  评论(0)    收藏  举报