Loading

题解:UVA10202 Pairsumonious Numbers

题目大意

\(n\) 个数两两相加,能得到 \(\dfrac{n\times(n-1)}{2}\) 个和。现在给你这 \(\dfrac{n\times(n-1)}{2}\) 个和,求原来的 \(n\) 个数。(多组数据测试)

解题思路

设原来的 \(n\) 个数为 \(a_1,a_2,\dots,a_n\)

\(m=\dfrac{n\times(n-1)}{2}\) 个和排序一下,得出序列 \(sum_1,sum_2,\dots,sum_m\)

最小的两个数是 \(sum_1=a_1+a_2\)\(sum_2=a_1+a_3\)

假设知道 \(a_1\),则能推出 \(a_2\)\(a_3\)

此时发现不知道 \(sum_3\)\(a_1+a_4\) 还是 \(a_2+a_3\)
但由于已知 \(a_2\)\(a_3\),则知道 \(a_2+a_3\)
可以直接把 \(a_2+a_3\)\(sum\) 中删除,\(sum\) 中剩下的 \(sum_3\)\(a_1+a_4\),知道了 \(a_4\)

同理,把 \(a_2+a_4\)\(a_3+a_4\)\(sum\) 中删除,剩下的 \(sum_4\)\(a_1+a_4\),就能知道 \(a_4\)

以此类推,每次把 \(a_2+a_i,a_3+a_i,\dots,a_{i-1}+a_i\)\(sum\) 中删除,剩下的 \(sum_{i-1}\) 即为 \(a_1+a_i\)

即每次把 \(a_1+a_i,a_2+a_i,\dots,a_{i-1}+a_i\)\(sum\) 中删除,剩下 \(sum\) 中最小的即为 \(a_1+a_i\)

用一个 set 维护 \(sum\) 就可以满足删除与查询操作了。

回到开头,因为不知道 \(a_1\),就直接枚举 \(a_1\)

因为 \(a_1<a_2,a_1+a_2=sum_1\),所以 \(a_1< \left\lfloor\dfrac{sum_1}{2}\right\rfloor\)

发现 \(sum_1\) 可能为负,则把 \(sum\) 中每一项都加上 \(-2\times sum_1\),这样能保证 \(a_1>0\),只需要在最后把求出的 \(a\) 每一项都加上 \(sum_1\) 即可。

代码

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=3e5+10;
const int N=3e5;
const int INF=0x3f3f3f3f;
const long long LINF=0x3f3f3f3f3f3f3f3f;
int n,num;
int a[MAXN],res[MAXN];
multiset <int> s;
void solve(){
    for(int i=1;i<=num;i++)
    {
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+num);
    int add=0;
    if(a[1]<0){
        add=-a[1];
    }
    for(int i=1;i<=num;i++)//全部加上-2a1
    {
        a[i]+=add*2;
        if(add==0){
            continue;
        }
    }
    for(int i=0;i<=a[1]/2;i++)//i为枚举的a1
    {
        s.clear();
        for(int j=1;j<=num;j++)
        {
        	s.insert(a[j]);
        }
        res[1]=i;
        bool flag=false;
        for(int j=2;j<=n;j++)
        {
        	res[j]=*s.begin()-i;//aj=当前最小值-a1
        	for(int k=1;k<j;k++)
        	{
        		multiset <int>::iterator it=s.find(res[j]+res[k]);//删去aj+ak
        		if(it==s.end()){//set中找不到aj+ak,Impossible
        			flag=true;
        			break;
        		}
        		s.erase(it);
        	}
        	if(flag){
        		break;
        	}
        }
        if(flag){
        	continue;
        }
        for(int j=1;j<n;j++)
        {
        	printf("%d ",res[j]-add);
        }
        printf("%d",res[n]-add);
        putchar('\n');
        return ;
    }
    puts("Impossible");
}
signed main(){
	while(~scanf("%d",&n))
	{
		num=n*(n-1)/2;
		solve();
	}
    return 0;
}
posted @ 2025-02-09 06:58  Mathew_Miao  阅读(14)  评论(0)    收藏  举报