【推导】【单调性】Petrozavodsk Winter Training Camp 2018 Day 1: Jagiellonian U Contest, Tuesday, January 30, 2018 Problem B. Tribute

题意:有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]," \n"[j==q]);
			//printf("%d %d %d\n",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]," \n"[i==n]);
		else printf("NO\n");
	}
	return 0;
}

/*
*/
posted @ 2018-04-15 20:25  AutSky_JadeK  阅读(244)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト