luogu P3643 [APIO2016]划艇
https://www.luogu.com.cn/problem/P3643
经典题
把范围离散化后转移可以做到\(O(n^3)\)
方案数可以用用组合数计算
code:
#include<bits/stdc++.h>
#define mod 1000000007
#define N 2005
#define ll long long
using namespace std;
int n, a[N], b[N], c[N], gs;
ll f[N], C[N], inv[N];
int main() {
scanf("%d", &n);
inv[1] = 1;
for(int i = 2; i <= n; i ++) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
for(int i = 1; i <= n; i ++) scanf("%d%d", &a[i], &b[i]), c[++ gs] = a[i], c[++ gs] = b[i] + 1;
sort(c + 1, c + 1 + gs);
gs = unique(c + 1, c + 1 + gs) - c - 1;
for(int i = 1; i <= n; i ++) {
a[i] = lower_bound(c + 1, c + 1 + gs, a[i]) - c;
b[i] = lower_bound(c + 1, c + 1 + gs, b[i] + 1) - c;
}
C[0] = f[0] = 1;
for(int j = 1; j < gs; j ++) {
int len = c[j + 1] - c[j];
for(int i = 1; i <= n; i ++) C[i] = C[i - 1] * (len + i - 1) % mod * inv[i] % mod;
for(int i = n; i >= 1; i --) if(a[i] <= j & j + 1 <= b[i]) {
int s = 1;
for(int k = i - 1; k >= 0; k --) {
(f[i] += f[k] * C[s] % mod) %= mod;
if(a[k] <= j && j + 1 <= b[k]) s ++;
}
}
}
ll ans = 0;
for(int i = 1; i <= n; i ++) ans = (ans + f[i]) % mod;
printf("%lld", ans);
return 0;
}