bzoj 2797 [Poi2012]Squarks 枚举一个,推出所有

题目大意

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

分析

首先我们假设x1<x2<x3..<xn是没问题的
那么两个数的和中最小的为x1+x2
次小的为x1+x3
现在考虑x2+x3的排名
比x2+x3小的一定是x1+xk
我们枚举x2+x3是哪一个值
可以解出x1,x2,x3
剩下的数中最小的为x1+x4
求出x4
同时可以算出x2+x4,x3+x4
除去已知的,剩下的数中最小x1+x5
依此类推

做法

我们考虑怎么找剩下的数
首先我们把所有的和插入set/heap里
每知道一个和就在里面删掉
考虑什么情况违法
x<0, xi-1==xi ,你求出来的和在原序列中不存在

solution

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int M=307;
 
inline int rd(){
    int x=0;bool f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(;isdigit(c);c=getchar()) x=x*10+c-48; 
    return f?x:-x;
}
 
int n,m;
int a[M];
int b[M*M];
 
int ans[M][M],tot;
 
struct cmp{
    bool operator () (int x,int y){
        return x>y;
    }
};
 
priority_queue<int,vector<int>,cmp>q,ers;
 
void gao(int d){
    int tp=b[1]+b[2]+d;
    if(tp&1) return;
    tp/=2;
    a[3]=tp-b[1];
    a[2]=tp-b[2];
    a[1]=tp-d;
     
    int cnt;
    int i,j,val;
     
    while(!q.empty()) q.pop();
    while(!ers.empty()) ers.pop();
    for(i=1;i<=m;i++) q.push(b[i]);
    ers.push(b[1]);
    ers.push(b[2]);
    ers.push(d);
     
    for(cnt=4;cnt<=n;cnt++){
        while(!ers.empty()){
            if(ers.top()==q.top()){
                ers.pop();
                q.pop();
            }
            else break;
        }
        val=q.top();q.pop();
        a[cnt]=val-a[1];
        for(j=2;j<cnt;j++) ers.push(a[j]+a[cnt]);
    }
     
    while(!ers.empty()){
        if(ers.top()==q.top()){
            ers.pop();
            q.pop();
        }
        else break;
    }
    if(!ers.empty()) return;
    for(i=1;i<=n;i++) if(a[i]<=0) return;
    for(i=2;i<=n;i++) if(a[i]==a[i-1]) return;
     
    tot++;
    for(i=1;i<=n;i++) ans[tot][i]=a[i];
}
 
int main(){
    int i,j;
    n=rd();
    m=n*(n-1)/2;
    for(i=1;i<=m;i++) b[i]=rd();
    sort(b+1,b+m+1);
     
    for(i=3;i<=n;i++)
        if(i==3||b[i]!=b[i-1]) gao(b[i]);
     
    printf("%d\n",tot);
    for(i=1;i<=tot;i++){
        for(j=1;j<=n;j++) printf("%d ",ans[i][j]);
        puts("");
    }
}
posted @ 2017-02-16 18:26  _zwl  阅读(267)  评论(0编辑  收藏  举报