hdu 5381 The sum of gcd

知道对于一个数列,如果以x为左(右)端点,往右走,则最多会有log(a[x])个不同的gcd,并且有递减性

所以会分成log段,每一段的gcd相同

那我们可以预处理出对于每一个位置,以这个位置为左端点和右端点的时候,分别产生的gcd的值和分界处

那么这道题就可以用莫队算法了,O(n * sqrt(n) * logn)

标程是用线段树

代码:

                                            
  //File Name: hdu5381.cpp
  //Author: long
  //Mail: 736726758@qq.com
  //Created Time: 2016年10月24日 星期一 11时36分49秒

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <vector>
#include <set>
#include <map>
#include <stdlib.h>
#define LL long long
#define pii pair<int,int>
#define fir first
#define sec second
#define mp make_pair
using namespace std;
const int MAXN = 10000 + 10;
int bel[MAXN],a[MAXN],cur_l,cur_r,tot;
LL ans[MAXN],cur_ans;
vector<pii> tol[MAXN],tor[MAXN];
struct Query{
    int l,r,t;
    bool operator < (const Query & x) const{
        if(bel[l] == bel[x.l]) return r < x.r;
        return bel[l] < bel[x.l];
    }
}que[MAXN];
int gcd(int x,int y){
    return y == 0 ? x : gcd(y, x % y);
}
void init(int n){
    pii now;
    for(int i=1;i<=n;i++){
        tol[i].clear();
        tol[i].push_back(mp(i,a[i]));
        if(i == 1) continue;
        int tot = 0,len = tol[i-1].size();
        for(int j=0;j<len;j++){
            now = tol[i-1][j];
            int d = gcd(now.sec,a[i]);
            if(d == tol[i][tot].sec)
                tol[i][tot].fir = now.fir;
            else{
                tol[i].push_back(mp(now.fir,d));
                tot++;
            }
        }
    }
    for(int i=n;i>0;i--){
        tor[i].clear();
        tor[i].push_back(mp(i,a[i]));
        if(i == n) continue;
        int tot = 0,len = tor[i+1].size();
        for(int j=0;j<len;j++){
            now = tor[i+1][j];
            int d = gcd(a[i],now.sec);
            if(d == tor[i][tot].sec)
                tor[i][tot].fir = now.fir;
            else{
                tor[i].push_back(mp(now.fir,d));
                tot++;
            }
        }
    }
}
LL gettol(int l,int r){
    LL res = 0;
    int pre = r,len = tol[r].size();
    for(int i=0;i<len;i++){
        pii now = tol[r][i];
        if(l < now.fir){
            res += (LL)(pre - now.fir + 1) * now.sec;
            pre = now.fir - 1;
        }
        else{
            res += (LL)(pre - l + 1) * now.sec;
            break;
        }
    }
    return res;
}
LL gettor(int l,int r){
    LL res = 0;
    int pre = l,len = tor[l].size();
    for(int i=0;i<len;i++){
        pii now = tor[l][i];
        if(r > now.fir){
            res += (LL)(now.fir - pre + 1) * now.sec;
            pre = now.fir + 1;
        }
        else{
            res += (LL)(r - pre + 1) * now.sec;
            break;
        }
    }
    return res;
}
void mover(int to){
    while(cur_r < to){
        cur_r++;
        cur_ans += gettol(cur_l,cur_r);
    }
    while(cur_r > to){
        cur_ans -= gettol(cur_l,cur_r);
        cur_r--;
    }
}
void movel(int to){
    while(cur_l < to){
        cur_ans -= gettor(cur_l,cur_r);
        cur_l++;
    }
    while(cur_l > to){
        cur_l--;
        cur_ans += gettor(cur_l,cur_r);
    }
}
void solve(int n,int q){
    init(n);
    int block = (int)sqrt(n + 0.5);
    for(int i=1;i<=n;i++)
        bel[i] = (n - 1) / block + 1;
    sort(que+1,que+q+1);
    cur_l = cur_r = 1,cur_ans = a[1];
    for(int i=1;i<=q;i++){
        mover(que[i].r);
        movel(que[i].l);
        ans[que[i].t] = cur_ans;
    }
    for(int i=1;i<=q;i++)
        printf("%I64d\n",ans[i]);
}
int main(){
    int t,n,q;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a + i);
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d %d",&que[i].l,&que[i].r);
            que[i].t = i;
        }
        solve(n,q);
    }
    return 0;
}
View Code

 

posted on 2016-10-26 14:40  _fukua  阅读(207)  评论(0编辑  收藏  举报