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明显智商不够用了。数论+块状数组#include <iostream> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <map> #include <cstdio> #include <cstring> #include <cmath> using namespace std; typedef long long LL; typedef pair<int,int> P; inline int read(){ int x = 0,f = 1; char ch = getchar(); while(ch < '0'||ch > '9'){if(ch == '-')f=-1;ch = getchar();} while(ch >= '0'&&ch <= '9'){x = x * 10 + ch -'0';ch = getchar();} return x*f; } // const int MAXN = 20000 + 10; struct Node{ int l,r,id,b; bool operator < (const Node& rhs)const{ if(b != rhs.b){ return b < rhs.b; } return r < rhs.r; } }query[MAXN]; vector<int> fact[MAXN]; int L,R; int phi[MAXN],num[MAXN]; int n,a[MAXN]; LL ans[MAXN]; void phi_table(){ for(int i = 1;i < MAXN;++i){ for(int j = i;j < MAXN;j += i){ fact[j].push_back(i); } } for(int i = 2;i < MAXN;++i) phi[i] = 0; phi[1] = 1; for(int i = 2;i < MAXN;++i)if(!phi[i]){ for(int j = i;j < MAXN;j += i) { if(!phi[j]) phi[j] = j; phi[j] = phi[j] / i * (i-1); } } } LL add(int x){ LL res = 0; for(int i = 0;i < (int)fact[x].size();++i) res += phi[fact[x][i]] * (num[fact[x][i]]++); return res; } LL del(int x){ LL res = 0; for(int i = 0;i < (int)fact[x].size();++i) res += phi[fact[x][i]] * (--num[fact[x][i]]); return res; } void solve(){ int Q = read(); int block_size = sqrt(1.0*n); for(int i = 0;i < Q;++i){ scanf("%d%d",&query[i].l,&query[i].r); query[i].b = query[i].l / block_size; query[i].id = i; } sort(query,query+Q); memset(num,0,sizeof(num)); LL res = 0; L = query[0].l; R = query[0].r; //预处理出第一个边界 for(int i = L;i <= R;++i){ res += add(a[i]); } ans[query[0].id] = res; int lb,ub; for(int i = 1;i < Q;++i){ lb = query[i].l; ub = query[i].r; //放大区间 while(lb < L) res += add(a[--L]); while(lb > L) res -= del(a[L++]); while(ub < R) res -= del(a[R--]); while(ub > R) res += add(a[++R]); ans[query[i].id] = res; } for(int i = 0;i < Q;++i) printf("%I64d\n",ans[i]); } int main() { phi_table(); // for(int i = 1;i < 10;++i) printf("%d ",phi[i]); int T; T = read(); for(int kase = 1;kase <= T;++kase){ n = read(); for(int i = 1;i <= n;++i){ //一定要根据题目查询区间的下标变化!!!!!!!! a[i] = read(); } printf("Case #%d:\n",kase); solve(); } return 0; } /* 1 5 3 2 5 4 1 3 1 5 2 4 3 3 */