题意真难读懂。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;
}