Just do it(异或的影响)

原题: https://cn.vjudge.net/problem/HDU-6129

题意:

有一个n长数组,m次操作,每次将当前数组转变成前缀数组。

解析:

观察m次操作后第一个数对后面每个位置的影响(异或两次等于没影响)

0: 1 0 0 0 0 0 0 0	
1: 1 1 1 1 1 1 1 1
2: 1 0 1 0 1 0 1 0
3: 1 1 0 0 1 1 0 0
4: 1 0 0 0 1 0 0 0
5: 1 1 1 1 0 0 0 0
6: 1 0 1 0 0 0 0 0
7: 1 1 0 0 0 0 0 0
8: 1 0 0 0 0 0 0 0

1: 1 1 1 1 1 1 1 1
2: 1 0 1 0 1 0 1 0
4: 1 0 0 0 1 0 0 0
8: 1 0 0 0 0 0 0 0

发现在第2^k次操作后,第一个位置对间隔k+1个位置有影响,而且影响可以叠加,所以我们可以把m分成二进制位。

对于第i位(从0开始),影响间隔为i+1,设为x,发现

1的影响:1->1+x 1+x->1+2x
2的影响:2->2+x 2+x->2+2x

假设x=1

1的影响:1->2 2->3
2的影响:2->3 3->3

所以我直接从2->3就可以把1和2的影响同时继承,所以遍历维护即可

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define debug(i) printf("# %d\n",i)

int a[1000009];

int main(){
    int t;scanf("%d",&t);
    while(t--){
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",a+i);
        }
        for(int i=0,j=1;j<=min(n,m);i++,j<<=1){
            if(m&j){
                for(int k=1;k<n;k++){
                    a[k+j]^=a[k];
                }
            }
        }
        for(int i=1;i<=n;i++){
            printf("%d%c",a[i],(i==n?'\n':' '));
        }
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/85108471