HDU

来源:互联网 发布:小熊电器网络广告语 编辑:程序博客网 时间:2024/06/06 13:17

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6085

题目大意:去找A数组模B数组后的值与k相等的个数,答案模2

官方题解:
这里写图片描述

解题思路:对于每个 B[i] 按其倍数分块,则对于 A[j] ∈ [x*B[i],(x+1)*B[i]) , A[j]%B[i] = A[j] - x*B[i],故事先将A数组处理成权值数组,枚举B[i] 和 B[i] 的每一个分块,将每个分块 [x*B[i],(x+1)*B[i]) 的值合并到 ans 的 [0, B[i]) 中对数组进行压位,压32位,这样合并起来快,对 l = x*B[i], r = (x+1)*B[i] 进行合并时,若l,r不为32的倍数,就非常麻烦,所以开32个压位数组,第i个数组存 l+i,这样就有一个数组满足 (l+i) % 32 == 0,容易合并,(r-l)% 32 != 0 时,多余的那部分手动合并

参考来源:http://www.cnblogs.com/nicetomeetu/p/7310593.html

AC代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 50000 + 5;unsigned a[32][MAXN], ans[MAXN];void toInit(){    memset(a, 0, sizeof(a));    memset(ans, 0, sizeof(ans));}void toSet(unsigned a[],int x){    a[x >> 5] ^= 1 << (31 & x);}bool toGet(unsigned a[], int x){    return a[x >> 5] & 1 << (31 & x);}void toSolve(int l,int r){    while ((r - l) & 31)    {        r--;        if(toGet(a[0],r)) toSet(ans, r - l);        }    int m = 0;    while (l & 31) l++, r++, m++;    l >>= 5, r >>= 5;    for (int i = l;i < r;++i)        ans[i - l] ^= a[m][i];}int main(){    int t;scanf("%d", &t);    while (t--)    {        toInit();        int n, m, q,mx=0;        scanf("%d%d%d", &n, &m, &q);        while(n--)        {            int x;scanf("%d", &x);            mx = max(mx, x);            for (int i = 0;i < 32;++i)                toSet(a[i], x + i);        }        while (m--)        {            int x;scanf("%d", &x);            for (int i = 0;i <= mx;i += x)                toSolve(i, min(i + x, mx + 1));        }        while (q--)        {            int x;scanf("%d", &x);            printf("%d\n", toGet(ans, x));        }    }    return 0;}
原创粉丝点击