您的位置:首页 > 其它

hdu 5481 Desiderium

2015-09-28 18:55 218 查看
题意真难读懂。Orz

一个含有n个区间的集合,从该集合中等概率地选取子集,求所有子集中的所有区间的构成的并集长度的和。

第二个样例解释:

集合中含有2个区间:一个是[0,2],编号为1,一个是[1,3],编号为2。

集合的子集有4个:

1、空集,集合中区间的并的长度为0

2、{区间1},集合中区间的并的长度为2

3、{区间2},集合中区间的并的长度为2

4、{区间1、区间2},集合中区间的并为[0,3],长度为3

考虑某一个区间对于答案的贡献:

若某个区间没有被其它区间覆盖,则该区间在子集中出现的总次数为:2^(n-1)次(总子集数-去掉该区间的子集总数)

若某个区间被覆盖了1次,即有2个区间重叠,那么该区间在子集中出现总次数为:2^(n-1)+2^(n-2)次(第1个区间在子集中出现的次数+第2个区间在子集中出现且第1个区间不出现的总次数)

…………

可以得到

若该区间被覆盖了k(k>=0)次,即有k+1个区间重叠,得到该区间在所有子集中出现的总次数:2^(n-1)+2^(n-2)+……+2^(n-k-1)

如何统计每一个区间的重叠次数?

对于输入的每一个区间的两个端点,给一个权值,左端点为1,右端点为-1。然后把所有端点按照位置从小到大排序。从左往右扫一遍,累加端点的权值,得到的当前的权值和就是当前所在区间的重叠次数。

累加每个区间的重叠次数*区间长度,即为所求。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
#define maxn 100005
#define mod 1000000007
struct P{
    int x,y;
}a[maxn<<1];
LL ans,sum[maxn],p[maxn];
bool cmp(P x,P y) {return x.x<y.x;}
int main()
{
    int T,i,n;
    scanf("%d",&T);
    p[0]=1;
    for(i=1;i<maxn;++i) p[i]=p[i-1]*2%mod;
    while(T--)
    {
        scanf("%d",&n);
        for(i=1;i<=n+n;i+=2){
            scanf("%d%d",&a[i].x,&a[i+1].x);
            a[i].y=1,a[i+1].y=-1;
        }
        sum[1]=p[n-1];
        for(i=2;i<=n;++i) sum[i]=(sum[i-1]+p[n-i])%mod;
        sort(a+1,a+n+n+1,cmp);
        int ans=0,cnt=0;
        for(i=1;i<n+n;++i){
            cnt+=a[i].y;
            ans=(ans+sum[cnt]*(a[i+1].x-a[i].x)%mod)%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: