码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5381 The sum of gcd

时间:2015-08-16 10:43:33      阅读:450      评论:0      收藏:0      [点我收藏+]

标签:

 题目大意:

 f(l,r)=ri=rj=gcd(ai,ai+1....aj)

求解多个区间 l , r 对应的f(l,r)值

 

这里首先要知道一个数的因子个数不超过log2(n)个,所以作为一个int整数来说,对应求得的最多只有31种gcd值

那么线段树上就可以维护这样的31种gcd值,并记录他们对应的数量

因为需要合并,所以要记录从左到右,和从右到左两种情况

这里我们其实很容易发现你一个个添加数的时候必然越往后区间段的gcd值越小,所以你保存进数组中对应的标号即为对应第几大的gcd值

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 
  5 using namespace std;
  6 #define N 10010
  7 #define ls o<<1
  8 #define rs o<<1|1
  9 #define LL long long
 10 #define M int m=(l+r)>>1
 11 
 12 int val[N] , n , q , s , t;
 13 
 14 int gcd(int a , int b){return b==0?a:gcd(b , a%b);}
 15 
 16 struct Node{
 17     int lf[32] , rg[32] , cntl , cntr , nl[32] , nr[32] ;
 18     LL sum;
 19 }tree[N<<2] , ans;
 20 
 21 Node Union(Node a , Node b)
 22 {
 23     //a是b左侧的区间节点
 24     Node ret;
 25     ret.sum = a.sum+b.sum;
 26     for(int i=1 ; i<=a.cntr ; i++){
 27         int k = a.rg[i];
 28         for(int j=1 ; j<=b.cntl ; j++){
 29             int tmp = gcd(k , b.lf[j]);
 30             ret.sum += (LL)tmp*a.nr[i]*b.nl[j];
 31         }
 32     }
 33     //更新从右侧出发的
 34     for(int i=1 ; i<=b.cntr ; i++) ret.rg[i] = b.rg[i] , ret.nr[i] = b.nr[i];
 35     int k = b.rg[b.cntr] , pos=b.cntr;
 36     for(int i=1 ; i<=a.cntr ; i++){
 37         int tmp = gcd(k , a.rg[i]);
 38         if(tmp == ret.rg[pos]) ret.nr[pos] += a.nr[i];
 39         else{
 40             pos++;
 41             ret.nr[pos] = a.nr[i];
 42             ret.rg[pos] = tmp;
 43         }
 44     }
 45     ret.cntr = pos;
 46 
 47     //更新从左侧出发的
 48     for(int i=1 ; i<=a.cntl ; i++) ret.lf[i] = a.lf[i] , ret.nl[i] = a.nl[i];
 49     k = a.lf[a.cntl] , pos = a.cntl;
 50     for(int i=1 ; i<=b.cntl ; i++){
 51         int tmp = gcd(k , b.lf[i]);
 52         if(tmp == ret.lf[pos]) ret.nl[pos] += b.nl[i];
 53         else{
 54             pos++;
 55             ret.nl[pos] = b.nl[i];
 56             ret.lf[pos] = tmp;
 57         }
 58     }
 59     ret.cntl = pos;
 60     return ret;
 61 }
 62 
 63 void build(int o , int l , int r)
 64 {
 65     if(l==r){
 66         tree[o].cntl = tree[o].cntr = 1;
 67         tree[o].sum = tree[o].lf[1] = tree[o].rg[1] = val[l];
 68         tree[o].nl[1] = tree[o].nr[1] = 1;
 69         return ;
 70     }
 71     M;
 72     build(ls , l , m);
 73     build(rs , m+1 , r);
 74     tree[o] = Union(tree[ls] , tree[rs]);
 75 }
 76 
 77 void query(int o , int l , int r , int s , int t)
 78 {
 79     if(l>=s && r<=t){
 80         if(l==s) ans = tree[o];
 81         else ans = Union(ans , tree[o]);
 82         return ;
 83     }
 84     M;
 85     if(m>=s) query(ls , l , m , s , t);
 86     if(m<t) query(rs , m+1 , r , s , t);
 87 }
 88 
 89 int main()
 90 {
 91   //  freopen("in.txt" , "r" , stdin);
 92     int T;
 93     scanf("%d" , &T);
 94     while(T--){
 95         scanf("%d" , &n);
 96         for(int i=1 ; i<=n ; i++) scanf("%d" , &val[i]);
 97         build(1,1,n);
 98      //   cout<<"in: "<<endl;
 99         scanf("%d" , &q);
100         while(q--){
101             scanf("%d%d" , &s , &t);
102             query(1 , 1 , n , s , t);
103             printf("%I64d\n" , ans.sum);
104         }
105     }
106     return 0;
107 }

 

HDU 5381 The sum of gcd

标签:

原文地址:http://www.cnblogs.com/CSU3901130321/p/4733701.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!