给定一个1-N的全排列序列,N<=20000,有Q组询问,Q<=20000,每组询问给出左右区间[l, r],calculate sum of gcd(a[i], a[j]) for every L <= i < j <= R.
已知数 A 的因子 d 在区间其他数中出现了 k 次,那么如果 d 是所有gcd(A, other)的值时,那么最终的结果加上k*d,但这是不一定的,且 d 的因子肯定也是 A 的因子,当枚举到 d 的因子 d' 时显然就不能够加了。
设每个因子一个容斥因子f(d)
使得 k*f(d) + k*f(d') + k*f(d'') + ... + k*f(1) = k*d,
这样如果 d 出现 k 次,那么其因子的因子等等就也会出现 k 次,而将他们都统计起来的最终结果就是等效于 k*d。可以证明f(d) = phi(d),后者为欧拉函数。
n = sum{phi(d) , d|n}
typedef long long LL ;
const int maxn = 20000 ;
vector <int> factor[maxn + 8] ;
LL phi[maxn + 8] ;
struct Q{
int l , r , id , p ;
friend bool operator < (const Q A , const Q B){
if(A.p == B.p) return A.r < B.r ;
else return A.p < B.p ;
}
}q[maxn + 8] ;
LL a[maxn + 8] ;
LL cnt[maxn + 8] ;
LL ans[maxn + 8] ;
int L , R ; LL sum ;
LL add(int x){
LL s = 0 ; int c ;
for(int i = 0 ; i < factor[x].size() ; i++){
c = factor[x][i] ;
s += cnt[c] * phi[c] ;
cnt[c]++ ;
}
return s ;
}
LL del(int x){
LL s = 0 ; int c ;
for(int i = 0 ; i < factor[x].size() ; i++){
c = factor[x][i] ;
cnt[c]-- ;
s += cnt[c] * phi[c] ;
}
return s ;
}
LL ask(int l , int r , int id){
int i ;
if(id == 0){
sum = 0 ;
for(i = l ; i <= r ; i++) sum += add(a[i]) ;
L = l , R = r ;
return sum ;
}
for(i = l ; i < L ; i++) sum += add(a[i]) ;
for(i = L ; i < l ; i++) sum -= del(a[i]) ;
for(i = R+1 ; i <= r ; i++) sum += add(a[i]) ;
for(i = r+1 ; i<= R ; i++) sum -= del(a[i]) ;
L = l , R = r ;
return sum ;
}
int main(){
int i , j ;
for(i = 1 ; i <= maxn ; i++){
for(j = i ; j <= maxn ; j += i)
factor[j].push_back(i) ;
}
for(i = 1 ; i <= maxn ; i++) phi[i] = i ;
for(i = 2 ; i <= maxn ; i++){
if(phi[i] == i){
for(j = i ; j <= maxn ; j += i)
phi[j] = phi[j]/i*(i-1) ;
}
}
int n , m , t , T = 1 ;
int blocksize ;
cin>>t ;
while(t--){
scanf("%d" , &n) ;
for(i = 1 ; i <= n ; i++) scanf("%I64d" ,&a[i]) ;
blocksize = sqrt(0.5 + n) ;
scanf("%d" , &m) ;
for(i = 0 ; i < m ; i++){
scanf("%d%d" , &q[i].l , &q[i].r) ;
q[i].id = i ;
q[i].p = q[i].l / blocksize ;
}
memset(cnt , 0 , sizeof(cnt)) ;
sort(q , q+m) ;
for(i = 0 ; i < m ; i++)
ans[q[i].id] = ask(q[i].l , q[i].r , i) ;
printf("Case #%d:\n" , T++) ;
for(i = 0 ; i < m ; i++) printf("%I64d\n" , ans[i]) ;
}
return 0 ;
}