Numbers
LsF wants to make some trouble. While zk is sleeping, Lsf mixed up sequence a and b with random order so that zk can't figure out which numbers were in a or b. "I'm angry!", says zk.
Can you help zk find out which n numbers were originally in a?
For each test case:
∙ The first line is an integer m(0≤m≤125250), indicating the total length of a and b. It's guaranteed m can be formed as n(n+1)/2.
∙ The second line contains m numbers, indicating the mixed sequence of a and b.
Each ai is in [1,10^9]
The first line is an integer n, indicating the length of sequence a;
The second line should contain n space-seprated integers a1,a2,...,an(a1≤a2≤...≤an) . These are numbers in sequence a.
It's guaranteed that there is only one solution for each case.
6 2 2 2 4 4 4 21 1 2 3 3 4 4 5 5 5 6 6 6 7 7 7 8 8 9 9 10 11
3 2 2 2 6 1 2 3 4 5 6
题意:
给定一个数列,其大小为m,规定其是数列a与数列b的混合数列(乱序)。其中数列a的长度为n,规定m满足n*(n+1)/2。另外,规定b数列是任意两个a[i]与a[j]的和(i不等于j)。求a数列的长度及数列元素。输出元素需从大到小排列。其中a数列与b数列中的元素均可重复。
思路:
由于给定的混合数列是乱序的,而我们需要输出一个有序的数列a,所以可以考虑用优先队列处理。
混合数列为a与b的混合,而数列b恰好是数列a中任意两个数的和。混合数列大小为m,数列a大小为n,由于m满足n*(n+1)/2,由计算可得数列b的大小为n*(n-1)/2,由此可得数列b为数列a中所有数的两两组合所得和。细想可知,混合数列由小到大排序后,最小的两个数一定是数列a中的元素。然后再将两数相加所得和必是数列b中的元素,也一定存在于混合数列中,所以把这个和在混合数列中删去。处理混合数列中的所有元素,判断是a中的元素还是b中的元素,把所有的和删去留下的就是数列a。
用一个优先队列存储混合数列ab,再用一个优先队列b存储现有a中所有元素两两结合后的所得和。先将ab中前两个元素弹出,再将这两个元素的和存在b中,比较b.top与ab.top,如果相等,则说明ab.top是b中的元素,不是a中的元素,所以直接弹出ab.top,再将b.top弹出;如果不相等,只能是ab.top<b.top,因为b中的元素一定全部存在在ab中,优先队列中所有元素有序,所以ab.top只能是小于等于b.top。当不等于时,说明ab.top是a中的元素,所以把ab.top加在a中,然后弹出ab.top。而每加入一个元素到a中,就要把这个元素与现存的a中的所有元素相加,再把所得和加入优先队列b中,再判断下一个元素是否与b.top相等。直到ab中所有的元素判断完为止。其中,当b数列为空时,说明当前a中的所有元素两两和都已经在ab中删去,所以ab.top一定为a中的元素。持续处理直至ab为空。
下面贴上代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=125500;
priority_queue<int, vector<int>,greater<int> > ab; //混合数列ab
priority_queue<int, vector<int>,greater<int> > b; //和集b
int a[maxn]; //a数列
int main()
{
int m;
while(~scanf("%d",&m))
{
int number;
for(int i=0; i<m; i++)
{
scanf("%d",&number);
ab.push(number);
}
//ab里面最小的两个数一定存在于a中
a[0]=ab.top();
ab.pop();
a[1]=ab.top();
ab.pop();
b.push(a[0]+a[1]);
int n=2; //数列a长度为n
while(!ab.empty())
{
if(b.empty()) //如果b为空,就直接将ab的top弹到a里面
{
a[n++]=ab.top();
for(int i=0; i<n-1; i++)
b.push(a[i]+ab.top());
ab.pop();
}
else if(ab.top()==b.top())
{
ab.pop();
b.pop();
}
else //由于m一定满足n(n+1)/2,则b中的数在ab中一定存在,又因为ab和b均为优先队列,故若ab.top!=b.top,则ab.top一定小于b.top,故直接将ab的top弹到a里面
{
a[n++]=ab.top();
for(int i=0; i<n-1; i++)
b.push(a[i]+ab.top());
ab.pop();
}
}
printf("%d\n",n);
for(int i=0; i<n-1; i++)
printf("%d ",a[i]);
printf("%d\n",a[n-1]);
}
return 0;
}