HDU 6129 规律+数论

来源:互联网 发布:itunes软件怎么下载 编辑:程序博客网 时间:2024/05/21 16:42

题意:

题目链接: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;}
原创粉丝点击