ZOJ Problem Set - 2892 Wavelet Compression
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1891
题意:给你一个最终的数组,求初始数组,初始数组转化为最终数组的过程如下。假设有a1,a2...a8
第一次:a1+a2,a3+a4,a5+a6,a7+a8,a1-a2,a3-a4,a5-a6,a7-a8这八个数,
第二次:a1+a2+a3+a4,a5+a6+a7+a8,a1+a2-a3-a4,a5+a6-a7-a8,a1-a2,a3-a4,a5-a6,a7-a8,
第三次:a1+a2+a3+a4+a5+a6+a7+a8,a1+a2+a3+a4-a5-a6-a7-a7,a1+a2-a3-a4,a5+a6-a7,a8,a1-a2,a3-a4,a5-a6,a7,a8;
知道最后一项的第一项是从a1加到a8的时候停止,然后给你最终数列,即第三次的结构,求a1~a8,
分析:先从简单的开始,就拿例子直接来,可以发现我们加入可以把第三项推到第二项,然后把第二项推到第一项,最后把第一项还原成最初项,答案就出来了。怎么把第三项还原成第二项?可以发现第三项前面两项相加除2就是第二项的第一个,相减除2就是第二项的第二个,然后其余的不变。然后第二项怎么还原成第一项,发现第二项的第一个加第三个除以2是第一项的第一个,相减除以2是第一项的第二个,那么规律就有了。假设第三项为第一层,我们只把i从1枚举到层数,然后ai+ai+层数/2就是下面的相对应的项,ai-ai+层数/2也是相对应的项,怎么知道相对应的项,,我是来个下标计算的,因为每次都是增加两个,且是递增的,所以只要把下标进行改变就可以知道对应的是下一层哪个项了,其中我还有个辅助数组,因为如果ai在计算时就改变肯定会影响最终 结果计算完成后,层数就要乘以2,因为是2倍改变,然后就可以啪啪啪,AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=300; int n; int ai[maxn]; int bi[maxn]; void init() { for(int i=1; i<=n; i++)scanf("%d",&ai[i]); } int ci[]= {1,2,4,8,16,32,64,128,256}; void play() { if(n==1) { printf("%d\n",ai[1]); return; } int e=0; for(int i=0; i<=8; i++) { if(ci[i]<<1==n) { e=i; break; } } for(int i=0; i<=e; i++) { int st=1; for(int j=1; j<=n; j++)bi[j]=ai[j]; for(int j=1; j<=ci[i]; j++) { int p=(ai[j]+ai[j+ci[i]])>>1; int q=(ai[j]-ai[j+ci[i]])>>1; bi[st]=p; bi[st+1]=q; st=st+2; } for(int j=1; j<=n; j++)ai[j]=bi[j]; } bool first=1; for(int i=1; i<=n; i++) { if(!first)printf(" "); first=0; printf("%d",ai[i]); } printf("\n"); } int main() { while(scanf("%d",&n)!=EOF) { if(n==0)break; init(); play(); } // cout << "Hello world!" << endl; return 0; }