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
原创粉丝点击