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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

BZOJ 2655 calc (组合计数、DP、多项式、拉格朗日插值)

發布時間:2025/3/15 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ 2655 calc (组合计数、DP、多项式、拉格朗日插值) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接

https://www.lydsy.com/JudgeOnline/problem.php?id=2655

題解

據說有一種神仙容斥做法,但我不會。
以及貌似網上大多數人的dp和我的做法都不一樣。

下面講我的做法:
首先由于元素互不相同,那么顯然可以先不考慮順序。
所以要求的就是\(n![x^n]\prod^{m}_{i=1}(1+ix)\) (直接莽上生成函數是不是有點……)
于是發現這個東西和第一類斯特林數生成函數幾乎一樣,也可以輕易寫出遞推式\(dp[i][j]=dp[i-1][j]+dp[i-1][j-1]\times i\)

有一個結論是,\(dp[i][j]\)是關于\(i\)的不超過\(2j\)次多項式。
感性理解的話,就是從\(1\)\(i\)里選\(j\)個,求乘積之和,\(1\)\(i\)里選\(j\)個一共有\(i\choose j\)種選法,這顯然是\(j\)次多項式,再求\(j\)個不超過\(i\)的數的乘積顯然也是\(j\)次,那么總共就是\(2j\)次。
于是求出前\(2n\)項,Lagrange插值計算即可。
(所以這其實是一種求第一類斯特林數\(\begin{bmatrix}n\\m\end{bmatrix}\) (\(n-m\)較小)的新方法?)

時間復雜度\(O(n^2)\).

代碼

#include<cstdio> #include<cstdlib> #include<cstring> #include<cassert> #include<iostream> #define llong long long using namespace std;const int N = 1000; llong fact[N+3],finv[N+3]; llong dp[N+3][N+3]; llong n,m,P;llong quickpow(llong x,llong y) {llong cur = x,ret = 1ll;for(int i=0; y; i++){if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}cur = cur*cur%P;}return ret; } llong mulinv(llong x) {return quickpow(x,P-2);}namespace Lagrange {llong ax[N+3],ay[N+3],poly[N+3];llong aux[N+3],aux2[N+3];void lagrange(int n){aux[0] = 1ll;for(int i=0; i<=n; i++){for(int j=i+1; j>0; j--){aux[j] = (aux[j-1]-aux[j]*ax[i]%P+P)%P;}aux[0] = P-aux[0]*ax[i]%P;}for(int i=0; i<=n; i++){llong coe = 1ll;for(int j=0; j<=n; j++){if(i==j) continue;coe = coe*(ax[i]-ax[j]+P)%P;}coe = mulinv(coe);for(int j=0; j<=n+1; j++) aux2[j] = aux[j];for(int j=n; j>=0; j--){poly[j] = (poly[j]+ay[i]*aux2[j+1]%P*coe)%P;aux2[j] = (aux2[j]+aux2[j+1]*ax[i])%P;}}}llong calc(int n,llong x){llong ret = 0ll;for(int i=n; i>=0; i--){ret = (ret*x+poly[i])%P;}return ret;}void clear(int n){for(int i=0; i<=n+1; i++) aux[i] = aux2[i] = poly[i] = 0ll;} }int main() {scanf("%lld%lld%lld",&m,&n,&P);fact[0] = 1ll; for(int i=1; i<=N; i++) fact[i] = fact[i-1]*i%P;finv[N] = quickpow(fact[N],P-2); for(int i=N-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;dp[0][0] = 1ll;for(int i=1; i<=n+n; i++){dp[i][0] = 1ll;for(int j=1; j<=i; j++){dp[i][j] = (dp[i-1][j]+dp[i-1][j-1]*i)%P;}}for(int i=0; i<=n+n; i++){Lagrange::ax[i] = i;Lagrange::ay[i] = dp[i][n];}Lagrange::lagrange(n+n);llong ans = Lagrange::calc(n+n,m)*fact[n]%P;printf("%lld\n",ans);return 0; }

總結

以上是生活随笔為你收集整理的BZOJ 2655 calc (组合计数、DP、多项式、拉格朗日插值)的全部內容,希望文章能夠幫你解決所遇到的問題。

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