HDU 6129 Just do it (机智)

Description

给出一个长度为\(n\)的非负整数数组\(a\),令\(b\)数组为\(a\)数组的前缀异或和,即\(b_i=a_1 \oplus a_2 \oplus \cdots \oplus a_i\),这样做\(m\)次,输出最终的\(b\)数组。

Input

第一行给出用例组数\(T\),对于每组用例,第一行给出\(n\)\(m\),第二行给出\(n\)个非负整数表示\(a\)数组。\(1 \leqslant n \leqslant 2 \times 10^5\)\(1 \leqslant m \leqslant 10^9\)

Output

对于每组用例,除数\(n\)个整数,表示求\(m\)遍异或和之后的\(b\)数组。

Sample Input

2
1 1
1
3 3
1 2 3

Sample Output

1
1 3 1

Solution

观察求每一遍异或前缀和后一个\(a_i\)\(b_j\)的贡献,发现每一个\(a_i\)贡献的数量构成杨辉三角,进一步总结后得出,求第\(m\)次异或前缀和后,\(a_i\)\(b_j\)贡献的数量为\(C(m+j-i-1,j-i)\)\(j \leqslant i\),即关于\(j-i\)的一个二项式系数,因为我们只关注二项式系数的奇偶性,有一个结论,\(C(a,b)\)是奇数当且仅当\(b\)的二进制表示中左右\(1\)的位置是\(a\)的二进制表示中所有\(1\)的位置的子集,即\(a\ and\ b = b\)。于是我们枚举\(j-i\)的值,记为\(k\),从\(0\)\(n-1\),仅当\(C(m+k-1,k)\)为奇数时更新\(b\)数组,为奇数的二项式系数并不多,可以在时间限制内完成。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;

int a[N], b[N];

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);
        memset(b, 0, sizeof(b));
        for (int k = 0; k < n; k++)
            if ((k & m + k - 1) == k)
                for (int i = 1; i + k <= n; i++) 
                    b[i + k] ^= a[i];
        for (int i = 1; i < n; i++) printf("%d ", b[i]);
        printf("%d\n", b[n]);
    }
    return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6129

转载于:https://www.cnblogs.com/dadamrx/p/7367716.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值