题解 P6146 【[USACO20FEB]Help Yourself G】
StudyingFather · · 题解
先将所有线段按左端点升序排序。
设
如果我们新添加了一条线段,复杂度会怎样变化呢?
- 不选这条线段。
这种情况下,复杂度没有变化,不包含这条线段的子集的复杂度仍然为
- 选这条线段。
复杂度分两部分:原来的复杂度(这部分不会因为新选一条线段而减少,因为线段已经按左端点排好顺序了)和新增加的复杂度(这条线段可能不与已有线段形成连通块)。
原来的复杂度仍然为
如果之前的线段中有
根据集合的知识,新增加的复杂度就是
从而得到递推式:
现在的问题就是计算
容易看出,设第
我们可以利用前缀和技巧来预处理所有
#include <iostream>
#include <algorithm>
#define MOD 1000000007
using namespace std;
struct seg
{
int l,r;
}a[100005];
int s[200005];
long long f[100005];
bool cmp(const seg&a,const seg&b)
{
return a.l<b.l;
}
long long fpow(long long x,long long y)
{
long long ans=1;
while(y)
{
if(y&1)ans=ans*x%MOD;
x=x*x%MOD;
y>>=1;
}
return ans;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].l>>a[i].r;
s[a[i].r]++;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=2*n;i++)
s[i]+=s[i-1];
for(int i=1;i<=n;i++)
f[i]=(2*f[i-1]+fpow(2,s[a[i].l-1]))%MOD;
cout<<f[n]<<endl;
return 0;
}