hdu 4913 Least common multiple(线段树)
来源:互联网 发布:java引用值 编辑:程序博客网 时间:2024/06/06 15:13
题意:给出n个数每个数以2^ai * 3^bi的形式给出,求这n个数所有的子集,并求子集的lcm的和。
思路:叉姐的题解看了半天还是没搞懂,罪过罪过Orz……不过还是提供了一些思路,对于一个选出的集合,它的lcm就等于2^max(ai) * 3^max(bi),那么,将ai从小到大排序,依次枚举,那么当前数和前面数组成的集合中,lcm的结果的2的幂次一定等于当前枚举的幂次,剩下的问题就是如何计算子集数和3的幂次。将每个数按bi的大小编号,每次要将这个数插入到其对应编号的位置,那么,我们就可以发现,当前要插入的数的位置,前面的数,3的幂次都小于等于它,后面的数,3的幂次都大于等于它。因此,对于前面的数,3的幂次就是当前枚举的幂次,后面的数,3的幂次是它们原来的幂次。这样,用线段树维护两个值,一个值是区间内的子集数,另一个数各子集的3的幂次的最大值的和。那么,每插入一个数,结果就要加上,它和它前面位置的数组成的集合的lcm,它和它后面位置的数组成的集合的lcm,它与它前面的一些集合与它后面的集合组成的集合的lcm。有了线段树维护的两个值,这个就不难求了。
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<stack>#include<set>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-8#define pi acos(-1.0)using namespace std;typedef long long ll;const int maxn=100000+10;const int mod=1000000000+7;ll pow_mod(ll x,ll n){ ll res = 1; while(n) { if(n & 1) res = res*x%mod; n>>=1; x= x*x%mod; } return res;}struct Node{ int a,b,id; Node(int a = 0,int b = 0,int id = 0):a(a),b(b),id(id){}}node[maxn];bool cmp1(Node x,Node y){ if(x.a == y.a) return x.id < y.id; return x.a < y.a;}bool cmp2(Node x,Node y){ if(x.b == y.b) return x.a < y.a; return x.b < y.b;}ll sum[maxn<<2],size[maxn<<2];void PushUp(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]*(size[rt<<1] + 1)%mod; sum[rt] %= mod; size[rt] = size[rt<<1] + size[rt<<1|1] + size[rt<<1]*size[rt<<1|1]%mod; size[rt] %= mod;}void build(int l,int r,int rt){ sum[rt] = size[rt] = 0; if(l == r) return ; int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1);}void Update(int p,int l,int r,int rt,ll v){ if(l == r) { sum[rt] = v; size[rt] = 1; return ; } int m = (l+r)>>1; if(m >= p) Update(p,l,m,rt<<1,v); else Update(p,m+1,r,rt<<1|1,v); PushUp(rt);}ll Query(int L,int R,int l,int r,int rt,ll & sz){ if(l >= L && r <= R) { sz = size[rt]; return sum[rt]; } int m = (l+r)>>1; if(m >= R) return Query(L,R,l,m,rt<<1,sz); else if(m < L) return Query(L,R,m+1,r,rt<<1|1,sz); else { ll res1,res2,sz1,sz2; res1 = Query(L,R,l,m,rt<<1,sz1); res2 = Query(L,R,m+1,r,rt<<1|1,sz2); sz = (sz1 + sz2 + sz1*sz2%mod)%mod; return (res1 + res2*(sz1+1))%mod; }}int main(){// freopen("in.txt","r",stdin);// freopen("out.txt","w ",stdout); int n; while(~scanf("%d",&n)) { for(int i = 1;i <= n;++i) scanf("%d%d",&node[i].a,&node[i].b); sort(node + 1,node + n +1,cmp2); for(int i = 1;i <= n;++i) node[i].id = i; sort(node + 1,node + n +1,cmp1); build(1,n,1); ll ans = 0,lsize,rval,tmp,p2,p3; int pos; for(int i = 1;i <= n;++i) { pos = node[i].id; p2 = pow_mod(2,node[i].a); p3 = pow_mod(3,node[i].b); Query(1,pos,1,n,1,lsize); ans += p2*p3%mod*(lsize + 1)%mod; rval = Query(pos,n,1,n,1,tmp); ans += p2*rval%mod; ans += p2*lsize%mod*rval%mod; ans %= mod; Update(pos,1,n,1,p3); } printf("%I64d\n",ans); } return 0;}
0 0
- 【HDU 4913】Least common multiple【线段树】
- hdu 4913 Least common multiple 线段树
- hdu 4913 Least common multiple(线段树)
- HDU 4913 Least common multiple 线段树
- HDU 4913 Least common multiple 解题报告(线段树)
- HDU 4913(Least common multiple-线段树+容斥)
- HDU 4913 Least common multiple
- [HDOJ 4913] Least common multiple [动态规划+线段树]
- hdu Least Common Multiple
- HDU Least Common Multiple
- HDU 1019 Least Common Multiple
- hdu 1019 Least Common Multiple
- HDU-1019 least common multiple
- HDU 1019 Least Common Multiple
- HDU 1019 Least Common Multiple
- HDU 1019 Least Common Multiple
- HDU 1019 Least Common Multiple
- hdu 1019Least Common Multiple
- codeforces 452E Three strings 后缀数组+并查集
- Splay Tree学习过程
- poj 1166 The Clocks
- C++中map容器的说明和使用技巧
- HDU 2546 饭卡 DP+01背包
- hdu 4913 Least common multiple(线段树)
- ios 指示器MBProgressHUD 的使用
- nyoj1038纸牌游戏(模拟题)
- SPOJ GNYR09F
- oracle 卸载
- javascript小白学习指南3
- 用ICE开发分布式程序
- Oracle将查询的结果放入一张自定义表中并再查询数据
- Secure CRT 常用操作