日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[APIO2016] 划艇(dp + 组合数 + 前缀和优化)

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [APIO2016] 划艇(dp + 组合数 + 前缀和优化) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

problem

luogu-P3643

solution

有個顯然的暴力 dpdpdp。設 dp(i,j):dp(i,j):dp(i,j): 到了第 iii 個學校,其參加且派出 jjj 個劃艇的方案數。

枚舉上一個參加的學校以及派出的劃艇,則有轉移:dp(i,j)=∑k<i,j<jdp(k,j′)dp(i,j)=\sum_{k<i,j<j} dp(k,j')dp(i,j)=k<i,j<j?dp(k,j)

可以再套個前綴和優化,但是由于第二維可以達到 1e91e91e9,并沒有起到關鍵性優化。

實際上我們并不關系真的派出了多少個劃艇,我們只在乎之間的滿足的遞增關系。

所以我們可以考慮離散化成 O(2n)O(2n)O(2n) 個端點。[ai,ai+1)→i[a_i,a_{i+1})\rightarrow i[ai?,ai+1?)i

f(i,j):f(i,j):f(i,j):iii 所學校中,第 iii 所學校參賽,且派出的劃艇數屬于第 jjj 個區間內的方案數。

  • Lemma:\text{Lemma}:Lemma: 從區間 [0,L][0,L][0,L] 中取 nnn 個數,要求所有非零數嚴格遞增,方案數為 (L+nn)\binom {L+n}n(nL+n?)

Proof:\text{Proof}:Proof:

  • 沒有 000 的情況,答案肯定是 (Ln)\binom Ln(nL?)。因為如果確定了一種組合,那么方案也隨之確定,即為這個組合的從小到大排列。所以這二者存在一一對應的關系。
  • 000 。觀察這個序列 0?0?0?...?0?1?2?...?L\text{0 0 0 ... 0 1 2 ... L}0?0?0?...?0?1?2?...?L。考慮從中選 nnn 個數,取某個非零數 iii 對應沒取 000 的第 iii 次選 iii

現在由于第 iii 所學校必須參賽,所以計算的時候 000 的個數 ?1-1?1。方案數即 (L+m?1m)\binom{L+m-1}m(mL+m?1?)

其中 mmm 表示選劃艇個數包含第 jjj 個區間的學校數量。

對于一個 kkk,對應方案數為 (L+m?1m)∑j′<jf(k,j′)\binom {L+m-1}m\sum_{j'<j}f(k,j')(mL+m?1?)j<j?f(k,j)

所以 f(i,j)=∑k<i(L+m?1m)∑j′<jf(k,j‘)f(i,j)=\sum_{k<i}\binom{L+m-1}{m}\sum_{j'<j}f(k,j‘)f(i,j)=k<i?(mL+m?1?)j<j?f(k,j)

此時再加前綴和優化,sum(k,j)=∑j′<jf(k,j′)sum(k,j)=\sum_{j'<j}f(k,j')sum(k,j)=j<j?f(k,j)

f(i,j)=∑k<i(L+mk?1mk)sum(k,j)f(i,j)=\sum_{k<i}\binom{L+m_k-1}{m_k}sum(k,j)f(i,j)=k<i?(mk?L+mk??1?)sum(k,j)

時間復雜度 O(n3)O(n^3)O(n3)

code

#include <bits/stdc++.h> using namespace std; #define maxn 1005 #define int long long #define mod 1000000007 int n; int a[maxn], b[maxn], c[maxn], x[maxn], inv[maxn], sum[maxn];signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) {scanf( "%lld %lld", &a[i], &b[i] );x[i] = a[i], x[i + n] = b[i] + 1;}sort( x + 1, x + (n << 1 | 1) );int m = unique( x + 1, x + (n << 1 | 1) ) - x - 1;for( int i = 1;i <= n;i ++ ) {a[i] = lower_bound( x + 1, x + m + 1, a[i] ) - x;b[i] = lower_bound( x + 1, x + m + 1, b[i] + 1 ) - x;}sum[0] = c[0] = inv[1] = 1;for( int i = 2;i <= n;i ++ ) inv[i] = (mod - mod / i) * inv[mod % i] % mod;for( int j = 1;j < m;j ++ ) {int len = x[j + 1] - x[j];for( int i = 1;i <= n;i ++ ) c[i] = c[i - 1] * (i + len - 1) % mod * inv[i] % mod;//組合數下標不變 所以可以每一次j區間變化時再求for( int i = n;i;i -- ) {//由于i與i-1及前面的掛鉤所以不能從前往后更新if( a[i] <= j and j + 1 <= b[i] ) {int o = 1, fi = 0; //o為滿足條件的個數 由于是從后往前的枚舉所以o單調遞增 每碰到一個合法的k o就要+1for( int k = i - 1;~ k;k -- ) {fi = (fi + sum[k] * c[o]) % mod;if( a[k] <= j and j + 1 <= b[k] ) o ++;}sum[i] = (sum[i] + fi) % mod;}}}int ans = 0;for( int i = 1;i <= n;i ++ ) (ans += sum[i]) %= mod;printf( "%lld\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的[APIO2016] 划艇(dp + 组合数 + 前缀和优化)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。