hdu 6085

多校第五场的1001Rikka with Candies是一道大数据量的计数题。

题意:给定A,B两个序列,有q个询问,每个询问给出一个k,问对于每一k,有多少种情况满足ai % bj = k?A,B的元素个数数据量均为50000,询问次数也为50000


分析:题目时限是3500ms,也就是算法只能是常数很小的n*n的算法才能勉强过掉,所以只能用bitset来加速计数,同时为了加速,必须避免大量使用取模运算,只能用以除数为单位采用加和的方式不断累加,这样可以不使用取模运算,同时这也是我第一次接触bitset,在比赛时并没有AC,之后看了很多博客了解了bitset的用法和大牛们关于这道题的解法,这里推荐一个我看到的博客【2017多校】HDU6085 Rikka with Candies 这个博客和我比赛时想到的思路差不多,但是比赛时我用bitset没有实现。

思路就是枚举余数k, 因为余数为k的条件是ai >= k, bj > k, 所以要从大到小枚举k,同时将上次枚举产生的倍速记录下来,这样bitsetz中记录的就是大于k的bj的倍数,然后和bitset-a做&运算就可以得到bj和a中共有的数字,这样bb & (a >> i)可以得到(a - i) % b = 0的数了,注意bitset右移i位就相当于所有的元素全部减少了i, 这样就可以得到每一个余数的计数答案了

  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstdlib>  
  4. #include <algorithm>  
  5. #include <cstring>  
  6. #include <map>  
  7. #include <set>  
  8. #include <vector>  
  9. #include <queue>  
  10. #include <cmath>  
  11. #include <bitset>  
  12.   
  13. using namespace std;  
  14.   
  15. bitset<50005>a, b, bb, ans;  
  16.   
  17. void solve(int maxk)  
  18. {  
  19.     bb.reset();  
  20.     ans.reset();  
  21.     for(int i = maxk; i >= 0; --i)  
  22.     {  
  23.         ans[i] = (bb & (a >> i)).count() & 1;  
  24.         if(b[i])  
  25.         {  
  26.             for(int j = 0; j <= 50000; j += i)  
  27.                 bb.flip(j);  
  28.         }  
  29.     }  
  30.     return;  
  31. }  
  32.   
  33. int main()  
  34. {  
  35.     int CASE;  
  36.     scanf("%d", &CASE);  
  37.     while(CASE--)  
  38.     {  
  39.         a.reset();  
  40.         b.reset();  
  41.         int n, m, q;  
  42.         scanf("%d%d%d", &n, &m, &q);  
  43.         int x;  
  44.         int maxx = 0;  
  45.         while(n--)  
  46.         {  
  47.             scanf("%d", &x);  
  48.             a.set(x);  
  49.         }  
  50.         while(m--)  
  51.         {  
  52.             scanf("%d", &x);  
  53.             b.set(x);  
  54.             maxx = max(maxx, x);  
  55.         }  
  56.         solve(maxx);  
  57.         while(q--)  
  58.         {  
  59.             scanf("%d", &x);  
  60.             printf("%c\n", ans[x] ? '1' : '0');  
  61.         }  
  62.     }  
  63.     return 0;  
  64. }  
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <cmath>
#include <bitset>

using namespace std;

bitset<50005>a, b, bb, ans;

void solve(int maxk)
{
    bb.reset();
    ans.reset();
    for(int i = maxk; i >= 0; --i)
    {
        ans[i] = (bb & (a >> i)).count() & 1;
        if(b[i])
        {
            for(int j = 0; j <= 50000; j += i)
                bb.flip(j);
        }
    }
    return;
}

int main()
{
    int CASE;
    scanf("%d", &CASE);
    while(CASE--)
    {
        a.reset();
        b.reset();
        int n, m, q;
        scanf("%d%d%d", &n, &m, &q);
        int x;
        int maxx = 0;
        while(n--)
        {
            scanf("%d", &x);
            a.set(x);
        }
        while(m--)
        {
            scanf("%d", &x);
            b.set(x);
            maxx = max(maxx, x);
        }
        solve(maxx);
        while(q--)
        {
            scanf("%d", &x);
            printf("%c\n", ans[x] ? '1' : '0');
        }
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值