题目: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代码:

 #include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define Mod 1000000007
using namespace std;
typedef long long LL; LL qpow(LL a,LL b)
{
LL ret=;
while(b)
{
if(b&) ret=ret*a%Mod;
a=a*a%Mod;
b>>=;
}
return ret;
} struct X
{
int id;
int a,b;
int ra; //a的排名
};
bool cmp1(X a,X b) //根据a排序
{
return a.a<b.a;
}
bool cmp2(X a,X b) //根据b排序
{
return a.b<b.b;
} X x[]; struct Node
{
LL sum,cnt;
LL mulCnt; //该区间乘了多少个2
int l,r;
int mid()
{
return (l+r)/;
}
};
Node v[];
void build(int l,int r,int rt)
{
v[rt].sum=v[rt].cnt=;
v[rt].mulCnt=;
v[rt].l=l;
v[rt].r=r;
if(l==r) return ;
build(l,v[rt].mid(),rt<<);
build(v[rt].mid()+,r,rt<<|);
} void push_down(int rt,bool flag)
{
if(v[rt].l==v[rt].r)
{
v[rt].mulCnt=;
return ;
}
v[rt<<].mulCnt+=v[rt].mulCnt;
v[rt<<|].mulCnt+=v[rt].mulCnt;
if(flag==)
{
v[rt<<].sum=v[rt<<].sum*qpow(,v[rt<<].mulCnt)%Mod;
push_down(rt<<,);
v[rt<<|].sum=v[rt<<|].sum*qpow(,v[rt<<|].mulCnt)%Mod;
push_down(rt<<|,);
}
v[rt].mulCnt=;
} LL look_cnt(int l,int r,int rt)
{
if(l==v[rt].l&&r==v[rt].r) return v[rt].cnt;
int mid=v[rt].mid();
if(l>mid) return look_cnt(l,r,rt<<|);
else if(r<=mid) return look_cnt(l,r,rt<<);
else return look_cnt(l,mid,rt<<)+look_cnt(mid+,r,rt<<|);
} LL look_sum(int l,int r,int rt)
{
if(l==v[rt].l&&r==v[rt].r)
{
v[rt].sum=v[rt].sum*qpow(2LL,v[rt].mulCnt)%Mod;
push_down(rt,);
return v[rt].sum;
}
push_down(rt,);
int mid=v[rt].mid();
LL ret;
if(l>mid) ret=look_sum(l,r,rt<<|);
else if(r<=mid) ret=look_sum(l,r,rt<<);
else ret=(look_sum(l,mid,rt<<)+look_sum(mid+,r,rt<<|))%Mod;
v[rt].sum=(v[rt<<].sum+v[rt<<|].sum)%Mod;
return ret;
} void update(int ra,int a,int rt)
{
if(v[rt].l==v[rt].r)
{
v[rt].cnt=;
LL x = ra== ? :look_cnt(,ra-,); //x 就是在a的前面(按b排序后)排名比a小的数量
v[rt].sum=qpow(,x+a);
v[rt].mulCnt=;
return ;
}
push_down(rt,);
if(ra<=v[rt].mid())
update(ra,a,rt<<);
else update(ra,a,rt<<|);
v[rt].cnt=v[rt<<].cnt+v[rt<<|].cnt;
v[rt].sum=(v[rt<<].sum+v[rt<<|].sum)%Mod;
} void mul(int l,int r,int rt)
{
if(v[rt].l==l&&v[rt].r==r)
{
v[rt].mulCnt++;
v[rt].sum=v[rt].sum*qpow(2LL,v[rt].mulCnt)%Mod;
push_down(rt,);
return ;
}
push_down(rt,);
if(r<=v[rt].mid()) mul(l,r,rt<<);
else if(l>v[rt].mid()) mul(l,r,rt<<|);
else
{
mul(l,v[rt].mid(),rt<<);
mul(v[rt].mid()+,r,rt<<|);
}
v[rt].sum=(v[rt<<].sum+v[rt<<|].sum)%Mod;
} int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
build(,n-,);
for(int i=;i<n;i++)
{
scanf("%d%d",&x[i].a,&x[i].b);
x[i].id=i;
}
sort(x,x+n,cmp1);
for(int i=;i<n;i++) x[i].ra=i;
sort(x,x+n,cmp2);
LL ans=;
for(int i=;i<n;i++)
{
update(x[i].ra,x[i].a,);
ans = (ans + look_sum(x[i].ra,n-,)*qpow(3LL,x[i].b))%Mod;
if(x[i].ra!=n-) mul(x[i].ra+,n-,);
}
printf("%I64d\n",ans);
}
return ;
}

HDU 4913 Least common multiple的更多相关文章

  1. HDU 4913 Least common multiple(2014 Multi-University Training Contest 5)

    题意:求所有自己的最小公倍数的和. 该集合是  2^ai  * 3^bi 思路:线段树. 线段树中存的是  [3^b * f(b)]   f(b)表示 因子3 的最小公倍数3的部分  为 3^b的个数 ...

  2. 背包系列练习及总结(hud 2602 && hdu 2844 Coins && hdu 2159 && poj 1170 Shopping Offers && hdu 3092 Least common multiple && poj 1015 Jury Compromise)

    作为一个oier,以及大学acm党背包是必不可少的一部分.好久没做背包类动规了.久违地练习下-.- dd__engi的背包九讲:http://love-oriented.com/pack/ 鸣谢htt ...

  3. HDU 1019 Least Common Multiple【gcd+lcm+水+多个数的lcm】

    Least Common Multiple Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Ot ...

  4. HDU 3092 Least common multiple 01背包

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3092 Least common multiple Time Limit: 2000/1000 MS ...

  5. hdu 2028 Lowest Common Multiple Plus(最小公倍数)

    Lowest Common Multiple Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  6. ACM hdu 1019 Least Common Multiple

    Problem Description The least common multiple (LCM) of a set of positive integers is the smallest po ...

  7. ACM学习历程—HDU 3092 Least common multiple(数论 && 动态规划 && 大数)

    Description Partychen like to do mathematical problems. One day, when he was doing on a least common ...

  8. HDU 2028 Lowest Common Multiple Plus

    http://acm.hdu.edu.cn/showproblem.php?pid=2028 Problem Description 求n个数的最小公倍数.   Input 输入包含多个测试实例,每个 ...

  9. HDU - 1019 - Least Common Multiple - 质因数分解

    http://acm.hdu.edu.cn/showproblem.php?pid=1019 LCM即各数各质因数的最大值,搞个map乱弄一下就可以了. #include<bits/stdc++ ...

随机推荐

  1. hover效果的几种方式

    1.改变透明度 #share_wrap a{display: inline-block;width: 48px;height: 44px;background: url(/images/finance ...

  2. UVA12558-Efyptian Fractions(HARD version)(迭代加深搜索)

    Problem UVA12558-Efyptian Fractions(HARD version) Accept:187  Submit:3183 Time Limit: 3000 mSec  Pro ...

  3. ORACLE直方图(10g)

    为什么需要直方图 ?当表中一列数据比较的值分布比较均匀时,optimzer可以很好的通过最大值,最小值和NDV(唯一值的个数),就可以判断出cardinality.对于cardinality越精确,o ...

  4. PHP消息队列的实现方式与详解,值得一看

    队列原理: 也是解耦的原理:业务系统和队列处理系统没有关系 一个写(业务系统),一个读(队列管理系统). 写的只管往队列里写,别的不用操心,读的能不能读完和写的也没有关系 同样,读的只管从队列里往外读 ...

  5. pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-使用说明

    初学时大多使用print或log调试程序,这在小规模的程序下很方便 但是更好的方法是一边运行一边检查里面的变量和方法 1.Pdb Pdb是一个交互式的调试工具,集成于Python标准库中 Pdb能让你 ...

  6. nginx让所有的http地址重定向到https

    问:为什么让所有的http都重定向到https呢?答:因为这样会使网站更安全些. 那么我是如何在nginx配置,让输入http://www.youcongtech.com或者youcongtech.c ...

  7. PAT A1052 Linked List Sorting (25 分)——链表,排序

    A linked list consists of a series of structures, which are not necessarily adjacent in memory. We a ...

  8. [MicroPython]TurnipBit开发板DIY自动浇水系统

    1.实验目的: ?学习在PC机系统中扩展简单I/O 接口的方法 ?学习TurnipBit拼插编程 ?学习土壤传感器的工作原理以及使用方法 2.所需原器件: TurnipBit一块 TurnipBit扩 ...

  9. 首页技术支持常见问题宽带外网IP显示为10、100、172开头,没有公网IP,如何解决?

    1.表现形式: 路由器拨号获得的公网IP变成了一个以100开头的IP(或者是10.172开头),而打开ip138.com查询却又是另外一个IP,将100开头的这个IP到百度去查询下则显示所在区域为美国 ...

  10. .net core 简单项目的创建

    1.linux 安装net coref https://www.microsoft.com/net/learn/get-started/linuxubuntu 2.创建目录 2.创建控制台项目 第一次 ...