[APIO2016][組合計數dp]划艇

一邊探索,一邊破壞

                        ——《巨齒鯊

離散成一些開區間;/*如果計數題數大區間少可以考慮這個思路,用組合數計數處理區間*/

用f[i][j][k]表示最後一個取到i這個學校,取值在第j段的,j段裏已經取了k個的方案數;

轉移,考慮前一個取到的學校;

f[i][j][k]=f[i−1][j][k]+f[i−1][j][k−1]∗(len[j]−k+1)/k
f[i][j][1]=f[i−1][j][1]+∑∑f[i−1][j′][k]∗len[j]
其中len[j]表示第j段包含整點個數。 
用前綴和優化第二個轉移   {注意這個區間處理,右邊部分+1,小處理避免重複}  {同時,前綴和優化只要對每個j記錄一個值即可,                                                                                                                                   想一想,處理起來麻煩就簡化了,事半功倍}

#include<bits/stdc++.h>
#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)
#define N 505
#define ll long long
#define mod 1000000007
using namespace std;
int n, tot, a[N], b[N], num[N<<1], g[N], C[N], inv[N];
int main() {
    scanf("%d", &n);
    inv[1] = 1; rep(i, 2, n) inv[i] = (ll)(mod-mod/i)*inv[mod%i]%mod;
    rep(i, 1, n) {
        scanf("%d%d", &a[i], &b[i]);
        num[++tot] = a[i]; num[++tot] = b[i]+1;
    }
    sort(num+1, num+1+tot); tot = unique(num+1, num+1+tot)-num-1;
    rep(i, 1, n) {
        a[i] = lower_bound(num+1, num+1+tot, a[i])-num;
        b[i] = lower_bound(num+1, num+1+tot, b[i]+1)-num;
    }
    C[0] = 1; g[0] = 1;
    rep(j, 1, tot-1) {
        int len = num[j+1]-num[j];
        rep(i, 1, n) C[i] = (ll)C[i-1]*(len+i-1)%mod*inv[i]%mod;
        per(i, n, 1) if(a[i] <= j && j+1 <= b[i]) {
            int f = 0, m = 1, c = len;//m是i-p
            per(p, i-1, 0) {
                f = (f+(ll)c*g[p]%mod)%mod;
                if(a[p] <= j && j+1 <= b[p]) c = C[++m];
            } g[i] = (g[i]+f)%mod;
        }
    }
    int ans = 0; rep(i, 1, n) ans = (ans+g[i])%mod;
    printf("%d\n", ans);
    return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章