題目定義了兩個東西.
第一個是 併, 併是指所有被至少一個線段覆蓋的點的集合.
第二個是複雜度, 複雜度是指這些並所形成的連通塊數目.
如何理解複雜度呢?
你可以想象為 一開始有兩條不想交的線段, 他們明顯沒有形成一個連通塊, 而他們兩個自己就是連通塊, 所以開始複雜度為2, 如果這個時候加入一條線段, 他跟其中一個線段相交了, 那麼他們就屬於一個連通塊了. 所以總共還是只有兩個連通塊.
那麼如何求出n條線段所有子集的複雜度之和呢?
每個線段本身就是一個子集.
我們把所有線段按左端點排個序, 這樣我們可以一個一個線段 慢慢加進我們的大集合中.
假設我們的大集合一開始是空集合, 每加入一個新的線段(子集), 只會發生兩種變化, 第一種變化是前面子集全部加1, 只有當前面的子集與新加入的子集沒有交集的時候才會. 第二種變化就是有交集不變. 所以 假設F(i) 為加入前 i 條線段的複雜度之和, F(i) 在加入新子集的複雜度變化是 2^x, x是沒有相交的線段數量. 當然還要加上原有的複雜度, F(i) = F(i - 1) + 2^x
我們的大集合中已經有很多子集了(線段), 我們可以不選擇把新子集和這些子集形成一個新的子集, 好比 我們有a 子集, 新進來b 子集, 他們可以形成 c 子集, 我們可以繼續保留 a b, 這就是不加入該子集的選擇, 所以就是繼承上一個狀態的大集合. F(i) = F(i - 1)
所以公式為F(i) = 2 * F(i - 1) + 2^x.
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#define MOD 1000000007
using namespace std;
typedef long long ll;
ll n;
struct node{
ll l, r;
}a[100002];
bool cmp(node &a, node &b){
return a.l < b.l;
}
ll preSum[200002];
ll f[100002];
ll qpow(ll x, ll y){
ll ans = 1;
while(y){
if(y & 1)ans = ans*x % MOD;
x = x * x % MOD;
y >>= 1;
}
return ans;
}
void work(){
memset(preSum, 0, sizeof(preSum));
cin >> n;
for(int i = 1; i <= n; i++){
int l, r;
cin >> a[i].l>> a[i].r;
preSum[a[i].r]++;
}
sort(a + 1, a + 1 + n, cmp);
for(int i = 1; i <= 2*n; i++){
preSum[i] += preSum[i - 1];
}
for(int i = 1; i <= n; i++){
f[i] = (2 * f[i - 1] + qpow(2, preSum[a[i].l - 1]))%MOD;
}
cout << f[n] << endl;
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
work();
return 0;
}