HDU 6129 规律+数论

题意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6129
给出一串长度为n的序列a,现在对a求m次前缀异或和,求最后得到的数组。


思路:

题目不长,但其实隐藏了很多知识点。
首先写几行找找规律:
a b c d
a ab abc abcd
a aab aaabbc aaaabbbccd
a aaab aaaaaabbbc aaaaaaaaaabbbbbbcccd
如果只看a的贡献,可以发现a对第x行,第y列的数的贡献系数是C(x+y-2,x-1),再来观察每个位置的a如果系数是xx,那么a之后的一个位置b的系数也是xx,同理c,d等系数都是xx,因此,只要求出来一个位置a的系数,那么对于之后的每个位置关于bcd的系数也都相同。因为这题需要算异或和,所以要知道组合数C(x+y-2,x-1)的奇偶性。
考虑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)判断组合数奇偶性了。


代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 10;

int a[MAXN], b[MAXN];

int main() {
    //freopen("in.txt", "r", stdin);
    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));
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            int x = i + m - 2, y = m - 1;
            if ((x & y) == y) {
                for (int j = i; j <= n; j++)
                    b[j] ^= a[j - i + 1], cnt++;
            }
        }
        //cout << cnt << endl;
        for (int i = 1; i <= n; i++)
            printf("%d%c", b[i], i == n ? '\n' : ' ');
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值