Sum Of Gcd
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 986 Accepted Submission(s): 465
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.
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.
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.
Sample Input
1
5
3 2 5 4 1
3
1 5
2 4
3 3
Sample Output
Case #1:
11
4
0
Source
2013 Multi-University Training Contest 8
关于一个区间内两两GCD之和,我们有一个推导:
对一个序列的某个区间L,R,每个数两两之间的GCD之和为
Σd|nφ(d)×C2num(d)
d: 这个区间的所有约数
通过这个公式,我们就可以很方便的通过枚举新加进来的数字的因子进行add和del,推算一下就可以了。
这里每个数的因子和欧拉函数要与处理一下保证复杂度。
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
const int maxn = 1e5+5;
struct data
{
int l,r,id;
}Q[maxn];
int pos[maxn];
int phi[maxn];
int pri[maxn];
int a[maxn];
int ans[maxn];
int Flag[maxn];
vector<int> v[maxn];
int num[maxn];
bool cmp(const data &a,const data &b)
{
if(pos[a.l]==pos[b.l]) return a.r<b.r;
return pos[a.l]<pos[b.l];
}
void Getphi(int Max)//欧拉函数与因子的预处理
{
phi[1] = 1;
for (int i = 2; i <= Max; i ++)
{
if (!Flag[i])
{
phi[i] = i - 1;
pri[++ pri[0]] = i;
}
for (int j = 1; j <= pri[0]; j ++)
{
if (1ll * i * pri[j] > Max) break;
Flag[i * pri[j]] = 1;
if (i % pri[j] == 0)
{
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
}
}
for(int i=1;i<=Max;i++)
{
for(int j=i;j<=Max;j+=i)
v[j].push_back(i);
}
}
int L=0,R=0;
long long Ans=0;
void add(int x)
{
for(int i=0;i<v[a[x]].size();i++)
Ans+=1LL*phi[v[a[x]][i]]*num[v[a[x]][i]];
for(int i=0;i<v[a[x]].size();i++)
num[v[a[x]][i]]++;
return ;
}
void del(int x)
{
for(int i=0;i<v[a[x]].size();i++)
num[v[a[x]][i]]--;
for(int i=0;i<v[a[x]].size();i++)
Ans-=1LL*phi[v[a[x]][i]]*num[v[a[x]][i]];
return ;
}
int main()
{
int n,q;
int t;
int cnt=1;
Getphi(20000);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
L=0,R=0,Ans=0;
for(int i=1;i<=n;i++) num[i]=0;
int sz=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[i]=i/sz;
}
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id=i;
}
sort(Q+1,Q+1+q,cmp);
for(int i=1;i<=q;i++)
{
while(R<Q[i].r)
{
R++;
add(R);
}
while(L>Q[i].l)
{
L--;
add(L);
}
while(L<Q[i].l)
{
del(L);
L++;
}
while(R>Q[i].r)
{
del(R);
R--;
}
ans[Q[i].id]=Ans;
}
printf("Case #%d:\n",cnt++);
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
}
return 0;
}