HDU - 4676 :Sum Of Gcd (莫队&区间gcd公式)
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.
InputFirst 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 a 1,a 2,...,a n.
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.OutputFor 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.Sample Input
1 5 3 2 5 4 1 3 1 5 2 4 3 3
Sample Output
Case #1: 11 4 0
题意:给定N个数,已经Q次询问,每次询问这个区间的两两GCD之和。
思路:之前做过一个类似的题,问区间两两有多少对互质,维护每个数的因子个数,即把下面的公式换成莫比乌斯系数瞎搞即可。
51nod1439:https://www.cnblogs.com/hua-dong/p/9141249.html
这里直接推。不过上次自己推的,这里我没有想出来,百度了一下。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=20010; struct in{int l,r,id;}s[maxn]; bool cmp(in w,in v){ if(w.l/100==v.l/100) return w.r<v.r; return w.l/100<v.l/100; } int a[maxn],ans[maxn],vis[maxn],phi[maxn]; int num[maxn],p[maxn],cnt,res; vector<int>G[maxn]; void solve() { phi[1]=1; for(int i=2;i<maxn;i++){ if(!vis[i]) p[++cnt]=i,phi[i]=i-1; for(int j=1;j<=cnt&&i*p[j]<maxn;j++){ phi[i*p[j]]=phi[i]*phi[p[j]]; vis[i*p[j]]=1; if(i%p[j]==0){phi[i*p[j]]=phi[i]*p[j]; break;} } } for(int i=1;i<maxn;i++){ for(int j=i;j<maxn;j+=i) G[j].push_back(i); } } void add(int x) { for(int i=0;i<G[x].size();i++){ res+=phi[G[x][i]]*num[G[x][i]]; } for(int i=0;i<G[x].size();i++) num[G[x][i]]++; } void del(int x) { for(int i=0;i<G[x].size();i++) num[G[x][i]]--; for(int i=0;i<G[x].size();i++){ res-=phi[G[x][i]]*num[G[x][i]]; } } int main() { solve(); int T,N,Q,L,R,C=0; scanf("%d",&T); while(T--){ scanf("%d",&N); rep(i,1,N) scanf("%d",&a[i]); scanf("%d",&Q); rep(i,1,Q) scanf("%d%d",&s[i].l,&s[i].r),s[i].id=i; sort(s+1,s+Q+1,cmp); L=0; R=0; res=0; memset(num,0,sizeof(num)); rep(i,1,Q){ while(L<s[i].l) del(a[L++]); while(R>s[i].r) del(a[R--]); while(L>s[i].l) add(a[--L]); while(R<s[i].r) add(a[++R]); ans[s[i].id]=res; } printf("Case #%d:\n",++C); rep(i,1,Q) printf("%d\n",ans[i]); } return 0; }