hdu6129 Just Do It!

多校时找规律做过。。。

题意,给你一个数列a[1], a[2], a[3], a[4], ... , a[n],操作一次后变为a[1], a[1] ^ a[2], a[1] ^ a[2] ^ a[3], ..., a[1] ^ a[2] ^ a[3] ^...^a[n],

让你计算出m次操作后的数列

令F(x, y, i) 表示x次操作后新的a[y]中初始 a[i]被亦或的次数

F(x, y, i) = F(x - 1, y, i) + F(x, y - 1, i)

联系几何意义,实际就是(1, i) 到 (x, y) 的路径条数,即 C(m - 1 + x - i, x - i)。

即可得到n^2的做法,猜想这些组合数中偶数很多,调整循环顺序,就AC了

这里判断组合数是否为偶数,采用了比较2的方幂的方法。

当然,也可以使用库摩尔定理(大概是15年联赛数论23333)

库摩尔定理:有两个正整数n,m,p是质数,C(n + m, m) 含p的幂次等于m+n在p进制下的进位数。

(在p进制下,产生一次进位,会贡献一个p)

当p为2时,若C(n + m, m)为奇数,则m+n不能产生进位,则意味着m数位为1的地方n必须为0,n数位为1的地方m必须为0,即 m & n = 0 

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 7;
int a[N], b[N];
#define rep(i, j, k) for (int i = int(j); i <= int(k); ++ i) 

inline int f(int x) {
    int ret = 0;
    while (x) {
        ret += (x >> 1);
        x >>= 1;
    }
    return ret;
}
inline int Comb(int n, int m) {
    return f(n) - f(m) - f(n - m);
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m;
        scanf("%d%d", &n, &m);
        rep(i, 1, n) scanf("%d", a + i);
        // rep(x, 1, n) {
        //     rep(i, 1, x) {
        //         if (!Comb(m  - 1 + x - i, x - i)) b[x] ^= a[i];
        //     }
        // }
        rep(j, 0, n - 1) 
        if (!Comb(m - 1 + j, j)) {
            rep(x, j + 1, n) {
                int i = x - j;
                b[x] ^= a[i];
            }
        }

        rep(i, 1, n - 1) printf("%d ", b[i]);
        printf("%d\n", b[n]);
        memset(b, 0, sizeof(b));
    }
}

 

转载于:https://www.cnblogs.com/tempestT/p/7668443.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值