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; }