题解: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;
}

浙公网安备 33010602011771号