我丟: https://www.luogu.com.cn/problem/P6144
先考慮 k = 1
考慮DP
首先將所有的線段按照左端點排序,考慮 表示最右以結尾的線段集合的連通塊的數量的和.
插入一個線段,
也就是要一個數據結構,支持區間*2,區間求和,顯然線段樹
對於k != 1, 可以考慮把它的 [0,k]次的結果分別維護,計算的時候用二項式定理合並就好了
就是線段樹每個點要維護各個次方的結果
看代碼好理解一點
code:
#include<bits/stdc++.h>
#define N 400005
#define int long long
#define mod 1000000007
using namespace std;
struct haha {
int a[13];
};
struct A {
int l, r;
} a[N];
int cmp(A x, A y) {
return x.l < y.l;
}
int ha[N << 3][12], tag[N << 3], n, k, C[25][25];
void update(int rt) {
for(int i = 0; i <= k; i ++)
ha[rt][i] = (ha[rt << 1][i] + ha[rt << 1 | 1][i]) % mod;
}
void pushdown(int rt) {
if(tag[rt] == 1) return;
tag[rt << 1] *= tag[rt], tag[rt << 1 | 1] *= tag[rt], tag[rt << 1 | 1] %= mod, tag[rt << 1] %= mod;
int t = 1;
for(int i = 0; i <= k; i ++)
ha[rt << 1][i] *= tag[rt], ha[rt << 1 | 1][i] *= tag[rt], ha[rt << 1][i] %= mod, ha[rt << 1 | 1][i] %= mod;
tag[rt] = 1;
}
void add(int rt, int l, int r, int x, haha b) {
if(l == r) {
for(int i = 0; i <= k; i ++) ha[rt][i] = (ha[rt][i] + b.a[i]) % mod;
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if(x <= mid) add(rt << 1, l, mid, x, b);
else add(rt << 1 | 1, mid + 1, r, x, b);
update(rt);
}
void mul(int rt, int l, int r, int L, int R) {
if(L > R) return;
if(L <= l && r <= R) {
tag[rt] = tag[rt] * 2 % mod;
int t = 1;
for(int i = 0; i <= k; i ++)
ha[rt][i] = ha[rt][i] * 2 % mod;
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if(L <= mid) mul(rt << 1, l, mid, L, R);
if(R > mid) mul(rt << 1 | 1, mid + 1, r, L, R);
update(rt);
}
haha query(int rt, int l, int r, int L, int R) {
if(L > R) {
haha b;
for(int i = 0; i <= k; i ++) b.a[i] = 0;
return b;
}
if(L <= l && r <= R) {
haha d;
for(int i = 0; i <= k; i ++) d.a[i] = ha[rt][i];
return d;
}
pushdown(rt);
int mid = (l + r) >> 1; haha ret;
ret.a[0] = 1;
for(int i = 0; i <= k; i ++) ret.a[i] = 0;
if(L <= mid) {
haha b = query(rt << 1, l, mid, L, R);
for(int i = 0; i <= k; i ++) ret.a[i] += b.a[i], ret.a[i] %= mod;
}
if(R > mid) {
haha b = query(rt << 1 | 1, mid + 1, r, L, R);
for(int i = 0; i <= k; i ++) ret.a[i] += b.a[i], ret.a[i] %= mod;
}
return ret;
}
signed main() {
scanf("%lld%lld", &n, &k); int lim = 2 * n;
for(int i = 0; i <= lim * 4; i ++) ha[i][0] = 0 ;
for(int i = 0; i <= k; i ++) C[i][0] = 1;
for(int i = 1; i <= k; i ++)
for(int j = 1; j <= i; j ++)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
for(int i = 1; i <= n; i ++) scanf("%lld%lld", &a[i].l, &a[i].r);
sort(a + 1, a + 1 + n, cmp);
haha d;
for(int i = 0; i <= k; i ++) d.a[i] = 0;
d.a[0] = 1;
add(1, 0, lim, 0, d);
for(int tt = 1; tt <= n; tt ++) {
int l = a[tt].l, r = a[tt].r;
haha b = query(1, 0, lim, 0, l - 1);
haha c;
for(int i = 0; i <= k; i ++) c.a[i] = 0;
for(int i = 0; i <= k; i ++){
int ret = 0;
for(int j = 0; j <= i; j ++)
c.a[i] += b.a[j] * C[i][j] % mod, c.a[i] %= mod;
}
b = query(1, 0, lim, l, r - 1);
for(int i = 0; i <= k; i ++) c.a[i] = (c.a[i] + b.a[i]) % mod;
add(1, 0, lim, r, c);
mul(1, 0, lim, r + 1, lim);
}
printf("%lld", query(1, 0, lim, 0, lim).a[k]);
return 0;
}
這一場就這題值得寫一下QWQ