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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【做题记录】 [HEOI2013]SAO

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【做题记录】 [HEOI2013]SAO 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

P4099 [HEOI2013]SAO

類型:樹形 \(\text{DP}\)

這里主要補充一下 \(O(n^3)\)\(\text{DP}\) 優化的過程,基礎轉移方程推導可以參考其他巨佬的博客(題解)。

\(f[x][p]\) 表示在以 \(x\) 為根的子樹中,\(x\) 在拓撲序排在第 \(p\) 個時的方案數。

轉移中設 \(x\) 在已經合并的拓撲序中排名為 \(p_1\) ,將要合并的子樹(以 \(ver\) 為根)中 \(ver\) 排名為 \(p_2\) ,合并后 \(x\) 排名為 \(p_3\)

列出轉移方程:(為了表示方便略去了取模操作)

  • \(x < ver\)\(x\) 應在 \(ver\) 之前,\(p_1<p_2\)
for(p1 = [1,siz[x]])for(p2 = [1,siz[ver]])for(p3 = [p1,p1+p2-1])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];
  • \(x > ver\)\(x\) 應在 \(ver\) 之后,\(p_1>p_2\)
for(p1 = [1,siz[x]])for(p2 = [1,siz[ver]])for(p3 = [p1+p2,siz[x]+siz[ver]])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];

(更直觀的轉移方程:)

\[f[x][p3]+=f[x][p1]\times f[ver][p2]\times C_{p3-1}^{p1-1}\times C_{siz[x]+siz[ver]-p3}^{siz[x]-p1} \]

到此為止,你可以得到 \(40pts\) 的好成績。

交換內外循環

可以觀察到 \(p_2\) 在轉移方程中只出現了一次,因此我們將 \(p_2\)\(p_3\) 的循環交換,列出轉移方程:

  • \(x < ver\)\(x\) 應在 \(ver\) 之前,\(p_1<p_2\)
for(p1 = [1,siz[x]])for(p3 = [p1,p1+siz[ver]-1])for(p2 = [p3-p1+1,siz[ver]])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];
  • \(x > ver\)\(x\) 應在 \(ver\) 之后,\(p_1>p_2\)
for(p1 = [1,siz[x]])for(p3 = [p1+1,p1+siz[ver]])for(p2 = [1,p3-p1])f[x][p3]+=f[x][p1]*f[ver][p2]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];

前綴和優化去掉一層循環

通過上一步的交換,發現 \(f[x][p3]\) 累加中的 \(p2\) 是一段連續的,并且滿足乘法結合律,聯想到前綴和優化。

\(g[x][p]\) 表示在以 \(x\) 為根的子樹中,\(x\) 在拓撲序排在 \(p\) 個時的方案數之和。

那么轉移方程變為:

  • \(x < ver\)\(x\) 應在 \(ver\) 之前,\(p_1<p_2\)
for(p1 = [1,siz[x]])for(p3 = [p1,p1+siz[ver]-1])g[x][p3]+=g[x][p1]*(g[ver][siz[ver]]-g[ver][p3-p1])*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];
  • \(x > ver\)\(x\) 應在 \(ver\) 之后,\(p_1>p_2\)
for(p1 = [1,siz[x]])for(p3 = [p1+1,p1+siz[ver]])g[x][p3]+=g[x][p1]*g[ver][p3-p1]*c[p3-1][p1-1]*c[siz[x]+siz[ver]-p3][siz[x]-p1];

記得在最后加上:

for(int i=1;i<=siz[x];i++) g[x][i]+=g[x][i-1];

所以這道題 \(AC\) 了。

注:轉移中為了維持方程的無后效性,應將 \(f\) 數組備份一遍。

\(100pts\) 完整代碼:

#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define Maxn 1005 #define mod 1000000007 inline int rd() {int x=0;char ch,t=0;while(!isdigit(ch = getchar())) t|=ch=='-';while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();return x=t?-x:x; } int t,n,tot; int dp[Maxn][Maxn],tmp[Maxn],c[Maxn][Maxn],siz[Maxn]; int hea[Maxn],nex[Maxn<<1],ver[Maxn<<1],edg[Maxn<<1]; void add(int x,int y,int d) {ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot,edg[tot]=d; } void dfs(int x,int fa) {siz[x]=1,dp[x][1]=1;for(int i=hea[x];i;i=nex[i]){if(ver[i]==fa) continue;dfs(ver[i],x);memcpy(tmp,dp[x],sizeof(dp[x]));memset(dp[x],0,sizeof(dp[x]));if(edg[i])for(int p1=1;p1<=siz[x];p1++)for(int p3=p1;p3<=siz[ver[i]]+p1-1;p3++)dp[x][p3]=(dp[x][p3]+1ll*tmp[p1]*(dp[ver[i]][siz[ver[i]]]-dp[ver[i]][p3-p1]+mod)%mod*c[p3-1][p1-1]%mod*c[siz[x]+siz[ver[i]]-p3][siz[x]-p1]%mod)%mod;elsefor(int p1=1;p1<=siz[x];p1++)for(int p3=p1+1;p3<=siz[ver[i]]+p1;p3++)dp[x][p3]=(dp[x][p3]+1ll*tmp[p1]*dp[ver[i]][p3-p1]%mod*c[p3-1][p1-1]%mod*c[siz[x]+siz[ver[i]]-p3][siz[x]-p1]%mod)%mod;siz[x]+=siz[ver[i]];}for(int i=1;i<=siz[x];i++) dp[x][i]=(dp[x][i]+dp[x][i-1])%mod; } int main() {//freopen(".in","r",stdin);//freopen(".out","w",stdout);c[1][0]=c[0][0]=1;for(int i=1;i<=1000;i++,c[i][0]=1)for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;t=rd();char c;while(t--){n=rd();memset(hea,0,sizeof(hea)),tot=0;memset(siz,0,sizeof(siz));for(int i=1,x,y;i<n;i++){x=rd()+1,cin>>c,y=rd()+1;add(x,y,c=='<'),add(y,x,c=='>');}dfs(1,0);printf("%d\n",dp[1][n]);}//fclose(stdin);//fclose(stdout);return 0; }

總結

以上是生活随笔為你收集整理的【做题记录】 [HEOI2013]SAO的全部內容,希望文章能夠幫你解決所遇到的問題。

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