hdu 5481 区间离散+组合

第二个样例解释:

集合中含有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;  
}  

你可能感兴趣的:(hdu 5481 区间离散+组合)