HDU6129 Just do it (找规律)

来源:互联网 发布:阿里云服务器登陆账号 编辑:程序博客网 时间:2024/05/19 13:09

【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6129

题目意思

有一个长度为n的整数序列a,对其做m次前缀异或和,求最终的序列。

解题思路

用i表示次数,用j表示位子。那么就可以得到a[i][j]=a[i][j-1]^a[i-1][j](自己写两个不难看出),接着有两种处理:
1. 根据上式可以得到a[1]对后面的异或次数为:

    1   1   1   1   1   1   1   1  ...    1   2   3   4   5   6   7   8   ...    1   3   6   10  15  21  28  36  ...    1   4   10  20  35  56  84  120  ...    .......

根据异或性质奇数异或一次,偶数相当没异或,上表可以相当于:

        1   1   1   1   1   1   1   1     ...        1   0   1   0   1   0   1   0    ...        1   1   0   1   0   1   0   1     ...        1   0   0   0   1   0   0   0    ...        ......

发现每2^n中间夹(2^n)-1个0,非2^n可以转化成(2^n1)^(2^n2)^…..相异或(如异或3次可以先异或2次在异或1次)。那么只要把m分解成2^n1+2^n2+2^n3….处理a[1+kn1],a[1+kn2],a[1+kn3]就好了(每次都把最前面的看做a[1]不断后推).具体见代码1;
2. 第二种把a[i][j]=a[i][j-1]^a[i-1][j]=a[i-1][j-1]^a[i][j-2]^a[i-1][j-1]^a[i-2][j]=a[i-2][j]^a[i][j-2] => a[i][j-2^n]^a[i-2^n][j].然后依旧分解m,从后往前处理。详见代码2(有些dp的思想);

代码部分

///代码1#include<bits/stdc++.h>using namespace std;#define ll long longconst int maxn = 2e5 + 1000;ll a[maxn];int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,m;        scanf("%d %d",&n,&m);        for (int i=0;i<n;i++)        {            scanf("%lld",&a[i]);        }        for (int k=0;(1<<k)<n;k++)   ///不断取2的k次方        {            if (m&(1<<k))    ///如果m分解的含2的k次方            {                for (int i=0;i<n;i++) ///0到n不断当做a[1]处理后面                {                    if (i+(1<<k)>n)   ///把隔2^k的数组异或一次                        break;                    a[i+(1<<k)]^=a[i];                }            }        }        for (int i=0;i<n;i++)            printf("%lld%c",a[i],i==n-1?'\n':' ');    }}
///代码2#include<bits/stdc++.h>using namespace std;const int N = 2e5+5;int a[N];int main(){    int T;    scanf("%d", &T);    while(T--)    {        int n, m;        scanf("%d%d", &n, &m);        for(int i = 0; i<n; i++) scanf("%d", a+i);        while(m)        {            int x = m&-m;  ///求m中含有最大2^k。            for(int j = x; j < n; j++)            {                a[j] ^= a[j-x];            }            m-= x;        }        for(int i = 0; i < n; i++)            printf("%d%c", a[i], i==n-1?'\n':' ');    }    return 0;}
原创粉丝点击