Just do it
题意:给出n个元素的数组a,让你异或m次得到新的数组b。 每一次得到的b[i]都是a[0]一直异或到a[i],然后把b赋值给a,循环m次得到b。
碰到异或的题,一定要考虑很重要的一个性质,a^b^b==a !!
就是说异或偶数次同一个数之后值不变!
对于这道题,我们可以考虑a的每一个数对b的影响。
对于a[1],b[i]异或a[1]的次数如下表:
第一次变换: 1 1 1 1 1
第二次变换: 1 2 3 4 5
第三次变换: 1 3 6 10 15
第四次变换: 1 4 10 20 35
可以发现,该表从左下往右上看是组合数表!于是我们可以通过求组合数轻松得到每一个数对后面的数的影响次数!
关键:如何判断影响次数的奇偶性!
这里用到了Lucas定理,简单来说就是C(x,y)是奇数当且仅当(x&y)==y。
稍微分析一下就可以得到,分析转自某大佬
考虑Lucas定理:C(n,m)%p = C(n/p,m/p) * C(n%p,m%p) % p
令p=2,则C(n,m)%2 =C (n/2,m/2) * C(n%2,m%2) % 2
n%2和m%2其实就是n和m的二进制最后一位,很显然,如果C(n,m)是奇数,当m的最后一位为1时,n的最后一位也必须为1,否则C(0,1)=0,那么C(n,m)%2=0,C(n,m)就是偶数了。对于n/2和m/2,其实就是n和m同时二进制右移一位,因此n和m的每一位都会成为最后一位来比较,根据上面得到的,所以m每个为1的二进制位,n在这一位也必须是1,否则C(n,m)就是偶数,这种要求等价于(n&m)==m。这样就可以O(1)判断组合数奇偶性了。
先贴上代码

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=2e5+10; 4 int a[maxn],b[maxn]; 5 int n,m; 6 int main(){ 7 int t; 8 scanf("%d",&t); 9 while(t--){ 10 scanf("%d%d",&n,&m); 11 for(int i=1;i<=n;i++){ 12 scanf("%d",&a[i]); 13 b[i]=0; 14 } 15 for(int i=1;i<=n;i++){ 16 int x=i+m-2; 17 int y=i-1; 18 if((x&y)==y){ 19 for(int j=i;j<=n;j++) b[j]^=a[j-i+1]; 20 } 21 } 22 for(int i=1;i<=n;i++) printf("%d%c",b[i],i==n?' ':' '); 23 } 24 return 0; 25 }