HDU6102(树状数组 + 容斥 + 离线处理)
来源:互联网 发布:淘宝装修店铺模板 编辑:程序博客网 时间:2024/06/07 18:00
GCDispower
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 141 Accepted Submission(s): 70
Problem Description
There is a mysterious organization called GCD. They get a permutation P, permutation is a sequence of length N, only consists of number 1 to N and each number appears only once.
They want to gain magic power from this permutation. For the interval [L, R] they can get power:
∑i=LR∑j=i+1R∑k=j+1R(gcd(P[i],P[j])==P[k])⋅P[k]
Now they have M queries, for each query can you help them calculate how many power they can get?
They want to gain magic power from this permutation. For the interval [L, R] they can get power:
Now they have M queries, for each query can you help them calculate how many power they can get?
Input
The first line is an integer T which indicates the case number.
And as for each case, first line is two integer N and M which indicates the length of permutation and number of query.
Next line is N integer which indicate the permutation P
Next M line, for each line is two integer L and R which indicate each query.
Limit
1≤T≤100
1≤N,M≤100000
1≤Pi≤N , for any pair (i,j) , Pi≠Pj
1≤Li≤Ri≤N
About 95% test case:1≤N≤1000
Other test case:1≤N≤100000
And as for each case, first line is two integer N and M which indicates the length of permutation and number of query.
Next line is N integer which indicate the permutation P
Next M line, for each line is two integer L and R which indicate each query.
Limit
About 95% test case:
Other test case:
Output
As for each case, you need to output M integer which indicate the answer of each query.
Sample Input
23 13 2 11 36 36 5 4 3 2 11 62 63 5
Sample Output
1850
Source
2017 Multi-University Training Contest - Team 6
题意:给你一个序列,然后给你若干个询问,每个询问一个区间[l,r],问你这个区间的价值是多少,一个区间的价值我们定义为,若这个区间存在一个三元组i, j, k,使得gc(a[i], a[[j]) == a[k],则这个区间的价值加上a[k],(刚开始为0)。
解题思路:我们肯定是要把这些询问离线处理,然后一个最重要的一点是要枚举a[k],从左到右,我们可以知道如果gcd(a[i], a[j]) == a[k],则a[i] / a[k], 与a[j] / a[k] ,一定互质,所以我们肯定要枚举a[k]的倍数,并且位置在k的前面,处理出所有的倍数之后,我们从右往左扫,假如我们每次知道当前有多少对互质的数假设为x,我们就知道对区间左端点的贡献为x * a[k],我们可以用一个树状数组,或者线段树来维护一下就行, 关键是怎样知道当前有多少对互质的数,我们可以用容斥求出,我们可以每次记录一个数进行素数分解之后的所有可能的质因子乘积,然后后面的数通过容斥原理,先进行素数分解,然后枚举gcd为他的每一个质因子的倍数,这些数一定与当前数不互质,用总的数的个数减去这些数就行,我们可以用容斥求这些集合的并。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 100000 + 10;int N, M;vector<int> prime[maxn];//素数分解,之后的质因子bool valid[maxn];//素数筛选int a[maxn];//原数组int Hash[maxn];//元素i在原数组的位置vector<pair<int, int>> query[maxn];//query[i]表示以i为右端点的区间,query[i][j].first表示询问id,query[i][j].second表示询问区间的左端点ll ans[maxn];//用于容斥的数组,ans[i]表示i在之前出现过的次数vector<pair<int, int>> status[maxn];//stastus[i][j].first表示状态的大小,second表示容斥的符号ll Tree[maxn];//树状数组ll result[maxn];//保存结果int temp[maxn];//辅助数组int lowbit(int x){ return x&(-x);}void add(int loc, ll value){ for(int i = loc; i <= N; i += lowbit(i)) { Tree[i] += value; }}void update(int l, int r, ll value){ add(l, value); add(r + 1, -value);}ll get(int loc){ ll res = 0; for(int i = loc; i >= 1; i -= lowbit(i)) { res += Tree[i]; } return res;}void updateAns(int x, ll value){ for(int i = 0; i < status[x].size(); i++) { ans[status[x][i].first] += value; }}ll getAns(int x){ ll res = 0; for(int i = 0; i < status[x].size(); i++) { res += ans[status[x][i].first] * status[x][i].second; } return res;}void initPrime(){ memset(valid, true, sizeof(valid)); for(int i = 0; i < maxn; i++) { prime[i].clear(); status[i].clear(); } for(int i = 2; i < maxn; i++) { if(valid[i]) { for(int j = i; j < maxn; j += i) { valid[j] = false; prime[j].push_back(i); } } } for(int i = 1; i < maxn; i++) { for(int j = 0; j < (1<<(prime[i].size())); j++) { status[i].push_back(make_pair(1, 1)); for(int k = 0; k < prime[i].size(); k++) { int num = (j>>k)&1; if(num) { status[i][j].first *= prime[i][k]; status[i][j].second *= -1; } } } }}void init(){ memset(Tree, 0, sizeof(Tree)); memset(ans, 0, sizeof(ans)); for(int i = 1; i <= N; i++) { query[i].clear(); }}int main(){ initPrime(); //cout<<"initPrime sucess"<<endl; int T; scanf("%d", &T); while(T--) { scanf("%d%d", &N, &M); init(); for(int i = 1; i <= N; i++) { scanf("%d", &a[i]); Hash[a[i]] = i; } int l, r; for(int i = 1; i <= M; i++) { scanf("%d%d", &l, &r); query[r].push_back(make_pair(i, l)); } for(int i = 1; i <= N; i++)//枚举左端点,计算对右端点的贡献 { int cnt = 0; for(int j = 2 * a[i]; j <= N; j += a[i])//枚举a[i]的倍数 { if(Hash[j] < i) temp[++cnt] = Hash[j]; } sort(temp + 1, temp + cnt + 1);//对位置进行排序,便于从右往左扫 ll sum = 0; temp[0] = 0; for(int j = cnt; j >= 1; j--) { sum += getAns(a[temp[j]] / a[i]) * a[i]; updateAns(a[temp[j]] / a[i], 1);//更新容斥 if(j != 1) update(temp[j - 1] + 1, temp[j], sum);//更新对左区间的贡献 else if(temp[1] == 1) update(1, 1, sum); else update(1, temp[1], sum); } for(int j = cnt; j >= 1; j--) { updateAns(a[temp[j]] / a[i], -1);//还原容斥 } for(int j = 0; j < query[i].size(); j++)//计算结果 { result[query[i][j].first] = get(query[i][j].second); } } for(int i = 1; i <= M; i++) { printf("%lld\n", result[i]); } } return 0;}
阅读全文
1 0
- HDU6102(树状数组 + 容斥 + 离线处理)
- hdu6102 容斥+树状数组 2017多校第六场1007
- hdu2492(树状数组+离线处理)
- MooFest(树状数组+离线处理)
- hdu5792树状数组+容斥
- 树状数组练习--Necklace(树状数组+离线处理)
- HDU 3874 树状数组 + 离线处理
- hdu4630 线段树||树状数组离线处理
- hdu4630(树状数组+离线处理)
- HDU 3333 树状数组+离线处理
- POJ 2481 - Cows 树状数组离线处理
- HDU 3874 Necklace 树状数组 + 离线处理
- HDU 3874 Necklace(树状数组+离线处理)
- POJ 1990 MooFest(树状数组+离线处理)
- hdu 3333 树状数组+离线处理
- hdu 3874 树状数组+离线处理
- hdu 5057(树状数组+离线处理)
- hdu 4417 树状数组 离线处理
- [P1979]华容道
- HDU 1232-畅通工程(并查集)
- Linux accept()/epoll_wait()惊群问题与解决方案
- 深度学习调参技巧
- Go 函数 学习笔记
- HDU6102(树状数组 + 容斥 + 离线处理)
- adb环境变量的配置
- Kali linux & Aircrack-ng 破解 WPA/WPA2 无线网络
- 中文乱码,修改tomcat配置文件消失的问题
- Raft 为什么是更易理解的分布式一致性算法
- linux下epoll模型accept并发问题
- Mysql之索引类型
- MySQL_001_基础_字符集
- Redis centos6.5安装