数学 模+位运算
来源:互联网 发布:淘宝网阿迪达斯不敢买 编辑:程序博客网 时间:2024/05/22 09:53
Rikka with Candies
转自:hnust_Derker模+位运算,现在还是不打能明白,先留个记录。
/**HDU 6085 Rikka with Candies题意:A数组n个数,B数组m个数,q个查询, 每次给出一个k,询问有多少对(i,j), 使得Ai % Bj = k, 输出对数对模2的值思路:首先,用一个vis数组01方式记录A数组中的数是否出现过,因为有Ai % Bj = k,所以也就是(Ai - k) % Bj = 0,不妨设Ai - k = x,那么Bj则是x的因子,因为是Ai % Bj = k,所以k一定比Bj小,即k的取值范围是[0, Bj)那么可以枚举每个x, 再枚举每个x的因子c,如果c不在B数组出现, 就不管它;否则的话,就在[0, Bj)中的每一个y的值, 对应的加上vis数组中x + y的值,举个例子:vis数组中对于6 7 8 9 10 11的出现情况是0 1 1 0 1 0对于x枚举到6,它的因子枚举到3(假设3在B数组存在)的时候,如果有(Ai - k) % 3 = 0,那么就是说,如果k可以取值,k在[0, 3)也就是[0, 2]的范围内,也就转换为Ai = x + k, 也就是6 + [0, 2],那么现在只需要看对应取值为k的时候,x + k(Ai)是否存在,如果存在那么k的值即可加上1, 因为此时(Ai, 3)形成了一对模为k的数设res数组是记录余数为k的对数, x=6,c=3的情况如下所示vis 6 7 8 9 10 11 0 1 1 0 1 0x+k 6 7 8 res[0, 1, 2] + vis[x + 0, x + 1, x + 2]= res[0, 1, 2] + vis[6, 7, 8]= res[0, 1, 2] + [0, 1, 1]就是说res[0]+0, res[1]+1, res[2]+1, 代表有(6+1)%3=0,(6+2)%3=0,即(7, 3)形成了一对余数为1的数,(8, 3)形成了一对余数为2的数还有因为直接相加复杂度是O(n^2),题目说只需要模2, 那么可以用异或来写,用异或的话也不可能一个一个来,所以就用将连续若干个01值压缩成一个整数来异或,这样就是O(n^2 / 32), 还有一点就是对于x=0,因为所有正整数都是0的因子,对0分开写,原式就是(0 + k) % Bj = k => k % Bj = k, 就是找在A数组中k存在的前提下,在B数组中找出比k大的数的数量加进res[k]即可**/#include<bits/stdc++.h>typedef long long ll;const int MAXN = 5e4 + 70;using namespace std;int a[MAXN], b[MAXN];int res[MAXN], vis[MAXN];vector<int> G[MAXN];ll dig[MAXN][35];set<int> st;ll ans[MAXN];void init() { for(int i = 1; i < MAXN - 3; i++) { for(int j = 1; j * j <= i; j++) { if(i % j) continue; G[i].push_back(j); if(i / j != j) G[i].push_back(i / j); } sort(G[i].begin(), G[i].end()); }}int main() { init(); int n, m, q, k, T; scanf("%d", &T); while(T--) { st.clear(); memset(vis, 0, sizeof vis); memset(res, 0, sizeof res); memset(ans, 0, sizeof ans); scanf("%d%d%d", &n, &m, &q); int max_data = -1; for(int i = 0; i < n; i++) { scanf("%d", &a[i]); vis[a[i]] = 1; max_data = max(max_data, a[i]); } for(int i = 0; i < m; i++) { scanf("%d", &b[i]); st.insert(b[i]); } sort(b, b + m); for(int i = 1; i <= 5e4; i++) { ll su = 0; for(int j = 0; j < 32; j++) { su = su * 2 + vis[i + j]; dig[i][j + 1] = su; dig[i][j + 1] <<= (31 - j); } } for(int i = 1; i <= max_data; i++) { for(int j = 0; j < G[i].size(); j++) { int x = G[i][j]; if(!st.count(x)) continue; int L = 0, R = x - 1; while(L <= R) { int d = L / 32; if(i + L > 5e4) break; if(R - L >= 31) { ans[d] ^= dig[i + L][32]; L += 32; } else { ans[d] ^= dig[i + L][R - L + 1]; L = R + 1; } } } } int num = 0; for(int i = 0; i * 32 <= 5e4; i++) { int j = (i + 1) * 32 - 1; int t = 32; while(t--) { res[j] = ans[i] & 1; j--; ans[i] >>= 1; } } for(int i = 0; i < n; i++) { int x = a[i]; res[x] += m - (upper_bound(b, b + m, x) - b); } while(q--) { scanf("%d", &k); printf("%d\n", res[k] & 1); } } return 0;}
阅读全文
0 0
- 数学 模+位运算
- 数学与位运算
- hdoj4810Wall Painting【组合数学+位运算】
- hdu4810 wall painting 组合数学+位运算
- 「算法」数学和位运算
- ZOJ3870 Team Formation【位运算+数学】
- 数学体操 模运算
- 运算符,位运算符,成员运算符,身份运算符,与数学函数
- hdu 4810 Wall Painting (位运算+组合数学)
- ZOJ 题目3870 Team Formation(数学,位运算)
- 【zzuliOJ】1893 - 985的数学难题(位运算)
- ZZULIOJ Problem 1893: 985的数学难题 【位运算】
- Problem B: 985的数学难题(位运算)
- [高频] 六.数学,几何计算,位运算常见问题
- 数学运算
- 巧妙的位运算及模运算
- 程序设计实习2016推荐练习3 硬币(dp+数学/位运算压位)
- 基础数学总结 关于模运算 1
- 考虑异常安全性的赋值语句
- for循环某个div
- laravel学习之路1:认证相关
- linux下nginx的简单安装
- 查询的某字段不为空的写法
- 数学 模+位运算
- Kruskal+二进制枚举 POJ 2784 Buy or Build
- 编程实现:《直通BAT面试算法精讲课》第一课:二叉树按层遍历
- 【golang】aws s3 go sdk
- [排序] 直接插入排序(Python)
- 如何下载通过 jitpack 发布的 jar
- centos 7 安装java redis
- html5 video 手机端视频播放全屏显示
- poj 3525 多边形内核,缩进