Sum Of Gcd

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
明显智商不够用了。数论+块状数组
#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
*/



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值