LXXV.[USACO20FEB]Help Yourself G
思路:
考虑将线段按照左端点排序。
设\(f[i]\)表示前\(i\)个线段的复杂度之和。
则\(f[i]=2*f[i-1]+2^{sum[l_i-1]}\)。其中\(sum_i\)是右端点\(\leq i\)的线段数目,\(l_i\)是\(i\)线段的左端点。
思考:
再往前的复杂度之和,无论第\(i\)根线段选与不选,都是无法改变的。因此要\(*2\)。
当之前的线段与线段\(i\)交集为空时,联通块新增一块。这部分共有\(2^{sum[l_i-1]}\)种选法。
复杂度\(O(n\log n)\)(排序是瓶颈,如果换成桶排就是\(O(n)\)的)
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,sum[200100],bin[100100],f[100100];
pair<int,int>p[100100];
int main(){
scanf("%d",&n),bin[0]=1;
for(int i=1;i<=n;i++)scanf("%d%d",&p[i].first,&p[i].second),sum[p[i].second]++,bin[i]=(bin[i-1]<<1)%mod;
for(int i=1;i<=2*n;i++)sum[i]+=sum[i-1];
sort(p+1,p+n+1);
for(int i=1;i<=n;i++)f[i]=(2ll*f[i-1]+bin[sum[p[i].first-1]])%mod;
printf("%d\n",f[n]);
return 0;
}