hdu6129 Just do it

来源:互联网 发布:云计算按使用者分 编辑:程序博客网 时间:2024/05/21 18:34

Just do it

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 836    Accepted Submission(s): 478



Problem Description
There is a nonnegative integer sequence a1...n of length n. HazelFan wants to do a type of transformation called prefix-XOR, which means a1...n changes into b1...n, where bi equals to the XOR value of a1,...,ai. He will repeat it for m times, please tell him the final sequence.
 

Input
The first line contains a positive integer T(1T5), denoting the number of test cases.
For each test case:
The first line contains two positive integers n,m(1n2×105,1m109).
The second line contains n nonnegative integers a1...n(0ai2301).
 

Output
For each test case:
A single line contains n nonnegative integers, denoting the final sequence.
 

Sample Input
21 113 31 2 3
 

Sample Output
1
1 3 1

题目大意:给你一个数列然你求m次前缀异或和。
解题思路:写一写前前几次的结果,观察规律
(以n=5,m=5为例)
An上面的系数代表这个数异或了几次。
把每一次的第i项a1异或的次数拿出来得到
1      1      1      1      1
1      2      3      4      5
1      3      6      10     15
1      4      10     20     35
1      5      15     35     70
.............................
发现斜着来的话是一个杨辉三角,第x次变换的第y项则系数为C(x+y-2,y-1)
知识点:1.一个数异或偶数次自己为0。2.一个数异或奇数次自己为其本身。3.一个数异或0为它本身。
也就是说当异或的次数为偶数时相当于没有异或,为奇数时相当于其本身,那么我们把每一次异或的系数求出判断它的奇偶性,并进行计算。比如上图m=5,n=5.我们要求第m次一伙的第1项时,算出C(4,0)=1,为奇数都有1这个系数,b[1]~b[5](最终要求的)异或上a[1]~a[5].第二项C(5,1)=5,为奇数,b[2]~b[5]分别异或a[1]~a[4],.............一直按这个规律求下去。


那么下面有一个问题就是说如何判断C(K,S)为奇数还是偶数,算出来,嗯,可以直观想法但当K,S很大时会爆的。有一个结论:如果K&S==S,那么C(K,S)为奇数。网上有一些证明,看懂了一点结合自己的看法证了一下,下面为证明过程。
证明:
对于给定C(K,S),检查n中2因子的个数与S和(K-S)中2因子个数和的关系,假设K!中2因子个数为a,S!中2因子个数为b,(K-S)!中2因子个数为c,则显然有a>=(b+c);并且当a==b+c时,一定为奇,否则为偶。题意转化为求a和b+c。



K!中含有2因子的个数等于(K-它的二进制形式中1的个数)  先证明这个小结论。
1.当K等于1时显然成立。
2.假设当K=P时也成立,即P=P二进制形式中1的个数(设为Pe)+P!中含有2因子的个数(设为Pg)。
3.当P为偶数时,P+1为奇数,那么(P+1)!中含有2因子的个数就为Pg,而(P+1)二进制形式中的1的个数为Pe+1.
所以,P+1=(P+1)二进制形式中1的个数(设为Pe1)+(P+1)!中含有2因子的个数(设为Pg1)

当P为奇数的时候,P+1假设进位为t(比如1001+1--->1010进位就为1,而1011111+1--->1100000进位为5)发现P+1二进制中1的个数比P二进制中1的个数少了t-1个,并且(P+1)中2因子的个数比P中2因子的个数多了t个(因为是奇数,所以为0),1011111----0个,1100000----2^5+2^6-----2^5(1+2^6)
因为我们假设P=Pe+Pg,那么P+1=Pe+Pg+1.而Pg1=Pg+t,Pe1=Pe-t+1,则P+1=Pe1+t-1+Pg1-t+1.即P+1=Pe1+Pg1.
由数学归纳法的得原结论:K!中含有2因子的个数等于(K-它的二进制形式中1的个数)成立。



a=K-K二进制形式中1的个数,b=S-K二进制形式中1的个数  ,c=K-S -(K-S)二进制形式中1的个数。
如果a=b+c(即C(K,S)为奇数)那么   K-K二进制形式中1的个数=S-S二进制形式中1的个数+K-S-(K-S)二进制形式中1的个数。化简得:
K二进制形式中1的个数-S二进制形式中1的个数=(K-S)二进制形式中1的个数。由此条件可得K&S==S即判断C(K,S)为奇数。
举个例子:K=1001101110
       S=      1101010   那么K-S   ->1000000100
这个时候   K二进制形式中1的个数-S二进制形式中1的个数=(K-S)二进制形式中1的个数  等价于  K&S==S 反之则不成立,有兴趣的可以自己模拟一下。
AC代码:
#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>using namespace std;int a[2050000];int b[2050000];int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,m;        scanf("%d%d",&n,&m);        memset(b,0,sizeof(b));        for(int i=1; i<=n; i++)            scanf("%d",&a[i]);        for(int i=1; i<=n; i++)        {            int y=i-1;            int x=i+m-2;            if((x&y)==y)///判断为奇数            {                for(int j=i; j<=n; j++)                    b[j]^=a[j-i+1];            }        }        for(int i=1; i<=n; i++)        {            printf("%d%c",b[i],i==n?'\n':' ');        }    }    return 0;}






原创粉丝点击