题意:有n个数,除了空集外,它们会形成2^n-1个子集,给你这些子集的和的结果,让你还原原来的n个数。
假设原数是3 5 16,
那么它们形成3 5 8 16 19 21 24,
那么第一轮取出开头的数(3),然后从当前最大的数(24)中减去它,然后必然会产生一个与其相等的数(21),将其一并删去(这个过程利用单调性,使用两个指针进行单调的从右向左的移动即可),然后将21进入下一轮的末尾……如此,3就是答案里的数。
下一轮变成 5 16 21……如此重复,每次序列长度减半,得到最终答案。
队友的代码:
#include <bits/stdc++.h> using namespace std; #define FOR(i,a,b) for (int i=(a);i<=(b);++i) #define ROF(i,b,a) for (int i=(b);i>=(a);--i) typedef long long LL; int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } const int MAXN=3000006; queue<int> Q; int n,m,q,a[MAXN],b[MAXN],c[MAXN]; void dfs(int x,int y){ if (x==n+1) { if (y) c[++q]=y; return; } dfs(x+1,y); dfs(x+1,y+b[x]); } int main() { int T=read(); while (T--) { n=read(); m=(1<<n); FOR(i,1,m-1) a[i]=read(); sort(a+1,a+m); while (!Q.empty()) Q.pop(); int flag=1; FOR(i,1,n) { b[i]=a[1]; q=0; int x=0,y=a[1]; ROF(j,m-1,2) { if (!x) if (!Q.empty()) x=Q.front(); else x=0; if (a[j]==x) c[++q]=a[j],Q.pop(),x=0; else Q.push(a[j]-y); } //FOR(j,1,q) printf("%d%c",c[j]," "[j==q]); //printf("%d %d %d ",Q.empty(),m/2-1,q); if (!Q.empty()||q!=m/2-1) { flag=0; break; } FOR(j,1,q) a[q+1-j]=c[j]; m>>=1; } if (flag) FOR(i,1,n) printf("%d%c",b[i]," "[i==n]); else printf("NO "); } return 0; } /* */