2017多校五 1001题 hdu 6085 Rikka with Candies 位运算 bitset
来源:互联网 发布:足彩数据app 编辑:程序博客网 时间:2024/06/01 08:30
题目链接
题意:
给定 a 数组长度 n ,和 b 数组长度 m,与若干个询问 q,每次询问有多少组 (i, j) 满足 a[i] % b[j] == k.
官方题解:
考虑预处理出所有 k 的答案,问题相当于一个模 2 意义下的 mod 卷积,即给出数组 A,B,将 Ai×Bj 累加到 wi mod j 上。
因为 i mod j=i−j⌊ji⌋,因此可以枚举 j 和 k=⌊ji⌋。这时相当与把 A 中区间 [kj,(k+1)j)中的所有数依次加到 w 的 [0,j) 区间上。
因为模 2 意义下的加法可以用异或实现,因此可以用压位来优化,这样时间复杂度为 ∑i=1nin×(32+32i),这约是 32n2。
注意因为 bitset 不支持提取区间操作,因此需要手写压位。如果不手写也可以用分块的方法来达到同样的复杂度但是常数比手写 bitset 大很多,可能需要一些常数优化才能通过时限。
然而手写压位什么的...0 0 标程写得太厉害了一时半会看不明白...等旅游回去定下心来看Orz
于是乎参考了众大神的 blog,发现分为两类,一类就是压位,另一类里面写得短而精炼。我便暂时就后者好好消化理解了一番。
考虑预处理出所有的 ans[k],因为每个算在 k 上面的答案,其来源只可能是 b 数组中 > k 的元素, 因此考虑从大到小枚举模数,这样每次算 k 时,所有对 k 有所影响的答案已经累计完毕。
事实上,计算是否有 a[i] % b[j] = k, 就相当于计算 a[i] - k 是否是 b[j] 的倍数;如果我们用一个数组 xx 将所有 b[j] 的倍数都标记为 1,则只要看 a[i] - k 的位置是否被标记为 1;再进一步,只要看 xx 数组移动 k 位 是否和 某些 a[ ] 相对应。
既然已经说到了 “移动” 和 “对应”,那么就和位运算挂上钩了,即 “左移” 和 “相与为1”。
用 aa 来将 a[ ] 的对应位 置1,那么上面描述的操作其实就是 (xx << k) & aa, 然后看得到的位串中有多少个 1,即为有多少对 (i, j),
故 ((xx << i) & aa).count() & 1 即为 (i, j) 对的个数 % 2.
刚才讲的并不严谨,事实上,我们对 b[j] 的倍数进行的操作并不是将其对应位 置1,而是进行翻转,因为其影响可能和之前的相抵消,这一点也很好理解。
这样,大神们的程序就解读完了,实在是太太太精妙了Orz.
压位等我之后再认真学习一发再来补Orz.
Code:
#include <bits/stdc++.h>#define maxn 50010using namespace std;bool ans[maxn], exist[maxn];bitset<maxn> aa, xx;inline int max(int a, int b) { return a > b ? a : b; }void work() { int n, m, q; scanf("%d%d%d", &n, &m, &q); int ma = 0, mb = 0; aa.reset(); xx.reset(); memset(exist, 0, sizeof(exist)); for (int i = 0; i < n; ++i) { int x; scanf("%d", &x); aa.set(x); ma = max(ma, x); } for (int i = 0; i < m; ++i) { int x; scanf("%d", &x); mb = max(mb, x); exist[x] = true; } for (int i = mb; i >= 0; --i) { ans[i] = ((xx << i) & aa).count() & 1; if (exist[i]) { for (int j = 0; j <= ma; j += i) xx.flip(j); } } while (q--) { int x; scanf("%d", &x); printf("%d\n", ans[x]); }}int main() { int T; scanf("%d", &T); while (T--) work(); return 0;}
- 2017多校五 1001题 hdu 6085 Rikka with Candies 位运算 bitset
- HDU 6085 Rikka with Candies 压位 bitset区间提取
- Hdu 6085 Rikka with Candies【思维+Bitset】
- hdu 6085 Rikka with Candies bitset
- HDU 6085 Rikka with Candies 模拟bitset
- HDU 6085 Rikka with Candies (bitset)
- HDU 6085 Rikka with Candies(bitset)
- HDU 6085 Rikka with Candies (bitset)
- hdu 6085 Rikka with Candies(bitset 计数原理)
- hdu 6085 Rikka with Candies(bitset容器)
- 【多校训练】hdu 6085 Rikka with Candies bitset
- HDU 6085 Rikka with Candies(bitset操作+思路转化)
- hdu 6085 Rikka with Candies bitset优化计数
- HDU 6085 Rikka with Candies (bitset, 2017 Multi-Univ Training Contest 5)
- 2017 Multi-University Training Contest 5 &&HDU 6085 Rikka with Candies 【bitset+思维】
- HDU 6085 Rikka with Candies(2017多校第五场)bitset枚举
- HDU 6085 Rikka with Candies
- HDU 6085 Rikka with Candies
- 出错总结(持续更新)欢迎提供建议
- 【Linux 学习】查看文件内容
- 两个变量实现交换
- 【 2017"百度之星"程序设计大赛
- Linux下面如何拷贝和删除隐藏的目录和文件
- 2017多校五 1001题 hdu 6085 Rikka with Candies 位运算 bitset
- mysql面试题总结
- 【HDU1402】 【FFT求大数乘法】
- 动态规划-背包问题
- ubuntu安装jdk8(亲测)
- 面向对象总结
- Matlab快速入门1——基础操作
- linux-http服务与配置
- 从文件中读数据并显示到控制台