zoukankan      html  css  js  c++  java
  • HDU 4913 Least common multiple

    题目:Least common multiple

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4913

    题意:有一个集合s,包含x1,x2,...,xn,有xi=2^ai * 3^bi,然后给你a数组和b数组,求s所有子集合的最小公倍数之和。比如S={18,12,18},那么有{18},{12},{18},{18,12},{18,18},{12,18},{18,12,18},所以答案是174。

    思路:

      1. 最小公倍数,因为xi只包含两个质因子2、3,那么子集合的最小公倍数其实就是2^max(a[]) * 3^max(b[])。max(a[])就是子集合相关的a数组集合中最大的ai。 

      2. 先简化题目,如果题目中的xi = 2^ai,那么可以对x数组进行从小到大排序。那么 lcm(x0,x1,...,xi)=xi,又 i 前面包含xi的子集合数量为2^(i-1)(其实就是xj(j<i)放入集合为1,不放入集合为0),那么最后的答案为 ∑ (2^ i-1 ) * xi,也就是ans[i]=ans[i-1]+2^(i-1)*2^(ai)

      3. 回归题目,题目中多了b数组,那么我们可以按b排序,令 x= i 前面 a的值小于ai的数量,令p1、p2、...、pk为i 前面 a的值比ai大的 位置。那么ans[i] = ans[i-1] + ( 2^x * 2^ai + 2^x * 2^ap1 + 2^(x+1) * 2^ap2 + ... + 2^(x+k-1) * 2^apk ) * 3^bi。

      3中的递推公式可以如下理解:

      推到i 就表示i 必选,那么i 前面最小公倍数为2^ai * 3^bi 的有 2^x 个,就是 x 个 a的值比ai小的xj 选与不选的问题了。比ai大的不选(因为选了的话,最小公倍数就不是xi了)

      然后xp1必选,也就是 第一个a的值比ai大的 xj必选,又 xi 必选,剩下x个比ai小的可选可不选,有2^x种情况,这2^x种情况的最小公倍数为2^ap1 * 3^bi。

      再接着xp2必选(注意:xi 还是必选,但xp1可选可不选),有2^(x+1)种情况,他们的最小公倍数为2^ap2 * 3^bi。

      。。。

      上面的递推公式只是告知ans[i]的算法,当然不能直接照样计算,因为即使你可以很容易得到 i 前面a值比ai大的位置,最坏情况下(b递增,a递减),时间复杂度也高达O(n*n)。

      现在我们可以维护2^x * 2^aj(其实就是维护那个x值),我们建一个线段树(离散型的),孩子结点(i,i)对应a值排名为i 的xj(x数组是按b排序的),线段树的结点包含sum、cnt和mulCnt三个属性,当遍历(从1-n)到j 时,xj对应的a值排名i的线段树结点cnt置1,sum置为2^x * 2^aj,然后向上更新,现在如果问x值,就可以用线段树很快地得出来。就是1-i 中cnt已经是1的数量。而2^x * 2^ap1 + 2^(x+1) * 2^ap2 + ... + 2^(x+k-1) * 2^apk可以通过维护得到,就是说每次计算完,从i+1到n的已经置为1(就是前面已经出现过的)的sum值乘2(因为比他们小的又多了一个aj,就是x+1)。

    AC代码:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<math.h>
      4 #include<algorithm>
      5 #define Mod 1000000007
      6 using namespace std;
      7 typedef long long LL;
      8 
      9 LL qpow(LL a,LL b)
     10 {
     11   LL ret=1;
     12   while(b)
     13   {
     14     if(b&1) ret=ret*a%Mod;
     15     a=a*a%Mod;
     16     b>>=1;
     17   }
     18   return ret;
     19 }
     20 
     21 struct X
     22 {
     23   int id;
     24   int a,b;
     25   int ra;           //a的排名
     26 };
     27 bool cmp1(X a,X b)  //根据a排序
     28 {
     29   return a.a<b.a;
     30 }
     31 bool cmp2(X a,X b)  //根据b排序
     32 {
     33   return a.b<b.b;
     34 }
     35 
     36 X x[100010];
     37 
     38 struct Node
     39 {
     40   LL sum,cnt;
     41   LL mulCnt;      //该区间乘了多少个2
     42   int l,r;
     43   int mid()
     44   {
     45     return (l+r)/2;
     46   }
     47 };
     48 Node v[400040];
     49 void build(int l,int r,int rt)
     50 {
     51   v[rt].sum=v[rt].cnt=0;
     52   v[rt].mulCnt=0;
     53   v[rt].l=l;
     54   v[rt].r=r;
     55   if(l==r) return ;
     56   build(l,v[rt].mid(),rt<<1);
     57   build(v[rt].mid()+1,r,rt<<1|1);
     58 }
     59 
     60 void push_down(int rt,bool flag)
     61 {
     62   if(v[rt].l==v[rt].r)
     63   {
     64     v[rt].mulCnt=0;
     65     return ;
     66   }
     67   v[rt<<1].mulCnt+=v[rt].mulCnt;
     68   v[rt<<1|1].mulCnt+=v[rt].mulCnt;
     69   if(flag==0)
     70   {
     71     v[rt<<1].sum=v[rt<<1].sum*qpow(2,v[rt<<1].mulCnt)%Mod;
     72     push_down(rt<<1,1);
     73     v[rt<<1|1].sum=v[rt<<1|1].sum*qpow(2,v[rt<<1|1].mulCnt)%Mod;
     74     push_down(rt<<1|1,1);
     75   }
     76   v[rt].mulCnt=0;
     77 }
     78 
     79 LL look_cnt(int l,int r,int rt)
     80 {
     81   if(l==v[rt].l&&r==v[rt].r) return v[rt].cnt;
     82   int mid=v[rt].mid();
     83   if(l>mid) return look_cnt(l,r,rt<<1|1);
     84   else if(r<=mid) return look_cnt(l,r,rt<<1);
     85   else return look_cnt(l,mid,rt<<1)+look_cnt(mid+1,r,rt<<1|1);
     86 }
     87 
     88 LL look_sum(int l,int r,int rt)
     89 {
     90   if(l==v[rt].l&&r==v[rt].r)
     91   {
     92     v[rt].sum=v[rt].sum*qpow(2LL,v[rt].mulCnt)%Mod;
     93     push_down(rt,0);
     94     return v[rt].sum;
     95   }
     96   push_down(rt,0);
     97   int mid=v[rt].mid();
     98   LL ret;
     99   if(l>mid) ret=look_sum(l,r,rt<<1|1);
    100   else if(r<=mid) ret=look_sum(l,r,rt<<1);
    101   else ret=(look_sum(l,mid,rt<<1)+look_sum(mid+1,r,rt<<1|1))%Mod;
    102   v[rt].sum=(v[rt<<1].sum+v[rt<<1|1].sum)%Mod;
    103   return ret;
    104 }
    105 
    106 void update(int ra,int a,int rt)
    107 {
    108   if(v[rt].l==v[rt].r)
    109   {
    110     v[rt].cnt=1;
    111     LL x = ra==0 ? 0 :look_cnt(0,ra-1,1);  //x 就是在a的前面(按b排序后)排名比a小的数量
    112     v[rt].sum=qpow(2,x+a);
    113     v[rt].mulCnt=0;
    114     return ;
    115   }
    116   push_down(rt,0);
    117   if(ra<=v[rt].mid())
    118     update(ra,a,rt<<1);
    119   else update(ra,a,rt<<1|1);
    120   v[rt].cnt=v[rt<<1].cnt+v[rt<<1|1].cnt;
    121   v[rt].sum=(v[rt<<1].sum+v[rt<<1|1].sum)%Mod;
    122 }
    123 
    124 void mul(int l,int r,int rt)
    125 {
    126   if(v[rt].l==l&&v[rt].r==r)
    127   {
    128     v[rt].mulCnt++;
    129     v[rt].sum=v[rt].sum*qpow(2LL,v[rt].mulCnt)%Mod;
    130     push_down(rt,0);
    131     return ;
    132   }
    133   push_down(rt,0);
    134   if(r<=v[rt].mid()) mul(l,r,rt<<1);
    135   else if(l>v[rt].mid()) mul(l,r,rt<<1|1);
    136   else
    137   {
    138     mul(l,v[rt].mid(),rt<<1);
    139     mul(v[rt].mid()+1,r,rt<<1|1);
    140   }
    141   v[rt].sum=(v[rt<<1].sum+v[rt<<1|1].sum)%Mod;
    142 }
    143 
    144 int main()
    145 {
    146   int n;
    147   while(scanf("%d",&n)!=EOF)
    148   {
    149     build(0,n-1,1);
    150     for(int i=0;i<n;i++)
    151     {
    152       scanf("%d%d",&x[i].a,&x[i].b);
    153       x[i].id=i;
    154     }
    155     sort(x,x+n,cmp1);
    156     for(int i=0;i<n;i++) x[i].ra=i;
    157     sort(x,x+n,cmp2);
    158     LL ans=0;
    159     for(int i=0;i<n;i++)
    160     {
    161       update(x[i].ra,x[i].a,1);
    162       ans = (ans + look_sum(x[i].ra,n-1,1)*qpow(3LL,x[i].b))%Mod;
    163       if(x[i].ra!=n-1) mul(x[i].ra+1,n-1,1);
    164     }
    165     printf("%I64d
    ",ans);
    166   }
    167   return 0;
    168 }
  • 相关阅读:
    eureka流程图
    Feign和Ribbon的重试机制
    idea编译kafka 2.6 源码
    Feign的调用流程
    FeignClientFactoryBean创建动态代理
    Feign源码的入口
    Ribbon的检查服务
    Ribbon是怎么和Eureka整合的?
    Eureka过期
    backup: sqlHelper --cSharp
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5704344.html
Copyright © 2011-2022 走看看