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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

CF1580B Mathematics Curriculum(笛卡尔树、树形dp)

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF1580B Mathematics Curriculum(笛卡尔树、树形dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

解析

比較巧妙的一道題。
難點在于對題意的轉化。

關鍵性質:符合要求的點等價于與笛卡爾樹上深度為 mmm 的點。

原因也較為顯然,考慮一個特定的點 xxx,當枚舉全局最大值時,其會對 xxx 產生貢獻,且最大值另一側就和 xxx 沒有關系了,向有 xxx 的一側遞歸尋找最大值計算貢獻,這個過程和笛卡爾樹的構造是一樣的。

問題就轉化為了:給定一個二叉樹,求第 mmm 層有 kkk 個節點的方案數。
這就是一個喜聞樂見的dp了。
設計狀態 dpi,j,sdp_{i,j,s}dpi,j,s? 表示子樹根節點深度為 jjj,子樹大小為 iii,且子樹內有 sss 個好點的方案數。
就有轉移:
fi,j,s=∑a=0i?1∑b=0a(i?1a)fa,j+1,b×fi?1?a,j+1,s?b?[j=m]f_{i,j,s}=\sum_{a=0}^{i-1}\sum_{b=0}^a\binom{i-1}{a}f_{a,j+1,b}\times f_{i-1-a,j+1,s-b-[j=m]}fi,j,s?=a=0i?1?b=0a?(ai?1?)fa,j+1,b?×fi?1?a,j+1,s?b?[j=m]?
直接做是 O(n5)O(n^5)O(n5) 的。
然后似乎也沒有什么辦法優化這個東西…于是就卡一卡常好了,調整一些變量的枚舉上界,再直接讓 fi,m,1=i!f_{i,m,1}=i!fi,m,1?=i!
然后就能卡過去了,最慢的點 1.7s1.7 s1.7s
(真不理解出題人為什么不能把范圍改成 808080 之類的,這種東西比賽時就算想到了也很可能不敢寫吧…)

代碼

#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) #define ok debug("OK\n") using namespace std;const int N=105;inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; }int mod;inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res; }int n,m,cnt; ll c[N][N],jc[N]; void init(int n){c[0][0]=1;for(int i=1;i<=n;i++){c[i][0]=1;for(int j=1;j<=i;j++){c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;}}jc[0]=1;for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;return; } ll f[N][N][N];signed main(){ #ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout); #endifn=read();m=read();cnt=read();mod=read();init(n);for(int i=0;i<=n;i++) f[i][m][min(i,1)]=jc[i];for(int j=m-1;j>=1;j--){f[0][j][0]=1;for(int i=1;i+(j-1)<=n;i++){for(int k=0;k<=min(cnt,i);k++){for(int a=0;a<i;a++){for(int b=0;b==0||b+m-(j+1)<=a;b++){(f[i][j][k]+=f[a][j+1][b]*f[i-1-a][j+1][k-b]%mod*c[i-1][a])%=mod;//printf("(%d %d %d) -< (%d %d %d)*(%d %d %d) add=%lld\n",i,j,k,a,j+1,b,i-1-a,j+1,m-)}}}}}//for(int j=1;j<=m;j++){// for(int i=0;i<=n;i++){// for(int k=0;k<=cnt;k++) printf("siz=%d dep=%d num=%d f=%lld\n",i,j,k,f[i][j][k]);// }//}printf("%lld\n",f[n][1][cnt]);return 0; } /* */

總結

以上是生活随笔為你收集整理的CF1580B Mathematics Curriculum(笛卡尔树、树形dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

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