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;
}
posted @ 2021-12-16 20:57  lahlah  阅读(31)  评论(0编辑  收藏  举报