【LOJ】#2567. 「APIO2016」划艇
阿新 • • 發佈:2018-12-18
題解
顯然有個很暴力的dp,\(dp[i][j]\)表示選到第\(i\)個數,末尾的數是\(j\)的方案數
但是第二維就開不下了,怎麼辦呢
考慮離散化整個區間,我們記錄\(dp[i][j][k]\)表示選到第\(i\)個點,選到第\(j\)個區間,這個區間選了\(k\)個數
轉移的時候記錄一個\(sum[j][k]\)表示\(i - 1\)之前的所有第二維等於\(j\),第三維等於\(k\)的值
\(dp[i][j][k] = sum[j][k]\)
顯然\(dp\)裡的數只會被算一次,所以存起來很浪費,可以去掉
然後每次轉移到下一種區間的時候乘上一個組合數,表示這個區間選\(k\)
轉移到下一種區間的時候也用字首和累加一下,用\(g[j]\)表示前\(i -1\)個數裡,第二維小於等於\(j\)的所有\(dp\)的和
程式碼
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define pdi pair<db,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') #define eps 1e-8 #define mo 974711 #define MAXN 505 //#define ivorysi using namespace std; typedef long long int64; typedef double db; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } const int MOD = 1000000007; int N; int a[MAXN],b[MAXN],C[MAXN * 2][MAXN]; int val[MAXN * 2],sum[MAXN * 2][MAXN],g[MAXN * 2],tot; int inv[MAXN]; int inc(int a,int b) { return a + b >= MOD ? a + b - MOD : a + b; } int mul(int a,int b) { return 1LL * a * b % MOD; } void update(int &x,int y) { x = inc(x,y); } void Init() { read(N); inv[1] = 1; for(int i = 2 ; i <= N ; ++i) inv[i] = mul(inv[MOD % i],MOD - MOD / i); for(int i = 1 ; i <= N ; ++i) {read(a[i]);read(b[i]);val[++tot] = a[i] - 1;val[++tot] = b[i];} sort(val + 1,val + tot + 1); tot = unique(val + 1,val + tot + 1) - val - 1; for(int i = 2 ; i <= tot ; ++i) { C[i][0] = 1; int t = val[i] - val[i - 1]; for(int j = 1 ; j <= N ; ++j) { C[i][j] = mul(C[i][j - 1],mul(inv[j],t - j + 1)); } } } void Solve() { int ans = 0; for(int i = 1 ; i <= N ; ++i) { int s = 1; for(int j = 2 ; j <= tot ; ++j) { int t = s;update(s,g[j]); if(a[i] <= val[j - 1] + 1 && b[i] >= val[j]) { for(int k = i - 1 ; k >= 1 ; --k) { update(sum[j][k + 1],sum[j][k]); update(ans,mul(sum[j][k],C[j][k + 1])); update(g[j],mul(sum[j][k],C[j][k + 1])); } update(ans,mul(t,val[j] - val[j - 1])); update(sum[j][1],t); update(g[j],mul(t,val[j] - val[j - 1])); } } } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Init(); Solve(); }