Numbers

来源:互联网 发布:java map 修改value值 编辑:程序博客网 时间:2024/05/16 18:36

Numbers

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 549    Accepted Submission(s): 291


Problem Description
zk has n numbers a1,a2,...,an. For each (i,j) satisfying 1≤i<j≤n, zk generates a new number (ai+aj). These new numbers could make up a new sequence b1b2,...,bn(n1)/2.
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?
 

Input
Multiple test cases(not exceed 10).
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]
 

Output
For each test case, output two lines.
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(a1a2...an). These are numbers in sequence a.
It's guaranteed that there is only one solution for each case.
 

Sample Input
62 2 2 4 4 4211 2 3 3 4 4 5 5 5 6 6 6 7 7 7 8 8 9 9 10 11
 

Sample Output
32 2 261 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; //混合数列abpriority_queue<int, vector<int>,greater<int> > b; //和集bint 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;}


原创粉丝点击