任意门:http://acm.hdu.edu.cn/showproblem.php?pid=4676
Sum Of Gcd
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 908 Accepted Submission(s): 438
Problem Description
Given you a sequence of number a1, a2, ..., an, which is a permutation of 1...n.
You need to answer some queries, each with the following format:
Give you two numbers L, R, you should calculate sum of gcd(a[i], a[j]) for every L <= i < j <= R.
You need to answer some queries, each with the following format:
Give you two numbers L, R, you should calculate sum of gcd(a[i], a[j]) for every L <= i < j <= R.
Input
First line contains a number T(T <= 10),denote the number of test cases.
Then follow T test cases.
For each test cases,the first line contains a number n(1<=n<= 20000).
The second line contains n number a1,a2,...,an.
The third line contains a number Q(1<=Q<=20000) denoting the number of queries.
Then Q lines follows,each lines contains two integer L,R(1<=L<=R<=n),denote a query.
Then follow T test cases.
For each test cases,the first line contains a number n(1<=n<= 20000).
The second line contains n number a1,a2,...,an.
The third line contains a number Q(1<=Q<=20000) denoting the number of queries.
Then Q lines follows,each lines contains two integer L,R(1<=L<=R<=n),denote a query.
Output
For each case, first you should print "Case #x:", where x indicates the case number between 1 and T.
Then for each query print the answer in one line.
Then for each query print the answer in one line.
Sample Input
1
5
3 2 5 4 1
3
1 5
2 4
3 3
Sample Output
Case #1:
11
4
0
Source
题意概括:
给出 1~N 的一个排列,M次查询,每次查询 L ~ R 内 GCD( ai, aj ) [ L <= i < j <= R ] 的总和。
解题思路:
又是涉及 GCD 又是 涉及区间查询,头有点大。
首先莫队处理区间查询,其次欧拉函数解决GCD问题。
根据:
那么用 gcd( ai, aj) 代替上式的 n,我们可以得到:
问题就转换成了求 d 的欧拉函数,其实 d 是有很多重复的,那么我们只要统计出当前查询区间【L,R】内 d 出现的次数然后乘上其欧拉函数值,所求的的答案就是区间GCD的总和。
欧拉函数值和对原序列的每一项的因数分解预处理时搞定。
AC code:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #include <cmath> 7 #define INF 0x3f3f3f3f 8 #define LL long long 9 using namespace std; 10 11 const int MAXN = 2e4+20; 12 int unit, a[MAXN], N, M, cnt[MAXN]; 13 LL ans[MAXN], phi[MAXN]; 14 vector<int>factor[MAXN]; 15 16 struct Query 17 { 18 int l, r, idx; 19 friend bool operator < (const Query & a, const Query & b){ 20 int x1 = a.l/unit, x2 = b.l/unit; 21 if(x1 != x2) return x1 < x2; 22 return a.r < b.r; 23 } 24 }Q[MAXN]; 25 26 void init() 27 { 28 for(int i = 1; i < MAXN; i++){ //分解因子 29 for(int j = i; j < MAXN; j+=i) 30 factor[j].push_back(i); 31 } 32 33 phi[1] = 1; //欧拉函数 34 for(int i = 2; i < MAXN; i++){ 35 phi[i] = i; 36 } 37 for(int i = 2; i < MAXN; i++){ 38 if(phi[i] == i){ 39 for(int j = i; j < MAXN; j+=i) 40 phi[j] = phi[j]/i*(i-1); 41 } 42 //puts("zjy"); 43 } 44 } 45 46 LL add(int x) 47 { 48 LL res = 0; 49 for(auto d : factor[x]) res+=cnt[d]*phi[d]; 50 for(auto d : factor[x]) cnt[d]++; 51 return res; 52 } 53 54 LL del(int x) 55 { 56 LL res = 0; 57 for(auto d : factor[x]) cnt[d]--; 58 for(auto d : factor[x]) res+=cnt[d]*phi[d]; 59 return -res; 60 } 61 62 63 void solve() 64 { 65 memset(cnt, 0, sizeof(cnt)); 66 int L = 1, R = 0; 67 LL cur = 0; 68 for(int i = 1; i <= M; i++){ 69 while( L < Q[i].l) cur += del(a[L++]); 70 while( L > Q[i].l) cur += add(a[--L]); 71 while( R < Q[i].r) cur += add(a[++R]); 72 while( R > Q[i].r) cur += del(a[R--]); 73 ans[Q[i].idx] = cur; 74 //puts("zjy"); 75 } 76 } 77 78 int main() 79 { 80 int T_Case, Cas = 0; 81 init(); 82 //puts("zjy"); 83 scanf("%d", &T_Case); 84 while(T_Case--){ 85 scanf("%d", &N); 86 for(int i = 1; i <= N; i++) scanf("%d", &a[i]); 87 scanf("%d", &M); 88 for(int i = 1; i <= M; i++){ 89 scanf("%d %d", &Q[i].l, &Q[i].r); 90 Q[i].idx = i; 91 } 92 unit = sqrt(N); 93 sort(Q+1, Q+1+M); 94 solve(); 95 printf("Case #%d: ", ++Cas); 96 for(int i = 1; i <= M; i++) printf("%lld ", ans[i]); 97 } 98 return 0; 99 }