zoukankan      html  css  js  c++  java
  • HDU 5381 The sum of gcd

     题目大意:

     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
    " , ans.sum);
    104         }
    105     }
    106     return 0;
    107 }
  • 相关阅读:
    c++学习笔记—二叉树基本操作的实现
    c++学习笔记—单链表基本操作的实现
    c++学习笔记—c++对txt文件的读取与写入
    c++学习笔记—动态内存与智能指针浅析
    c++学习笔记——个单词转换的map程序详解
    获取JAVA[WEB]项目相关路径的几种方法
    Oracle数据库体系结构及创建表结构
    锋利的jQuery学习总结
    SQL调优常用方法
    Oracle行转列操作
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4733701.html
Copyright © 2011-2022 走看看