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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

[树形dp] Jzoj P5233 概率博弈

發布時間:2023/11/27 生活经验 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [树形dp] Jzoj P5233 概率博弈 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Description

小A和小B在玩游戲。這個游戲是這樣的:
有一棵n個點的以1為根的有根樹,葉子有權值。假設有m個葉子,那么樹上每個葉子的權值序列就是一個1->m 的排列。
一開始在1號點有一顆棋子。兩人輪流將這顆棋子移向其當前位置的一個兒子。假如棋子到達葉子,游戲結束,最終獲得的權值為所在葉子對應權值。
小A希望最后的權值盡量大,小B希望盡量小。小A是先手。
在玩了很多局游戲后,小B對其中絕大多數局游戲的結果不滿意,他覺得是小A對葉子權值做了手腳。于是他一怒之下,決定將葉子的權值隨機排列。現在小B想知道,假如葉子的權值是隨機排列的(即葉子權值的每種排列都以等概率出現),那么游戲期望的結果是多少?
請輸出答案乘上m! 對10^9+7取模的結果,顯然這是一個整數。

Input

輸入文件名為game.in。
第一行包含一個整數n。
接下來n-1行,每行兩個整數u,v,表示有一條連接節點u,v的邊。

Output

輸出文件名為game.out。
輸出一個整數,表示答案。

Sample Input

輸入1:
5
1 2
2 3
1 4
2 5輸入2:
10
10 7
7 6
10 2
2 3
3 8
3 1
6 9
7 5
1 4

Sample Output

輸出1:
14輸出2:
74

Data Constraint

對于10%的數據,n<=5
對于30%的數據,n<=10
對于60%的數據, n<=50
對于100%的數據,n<=5000,保證給出的是一棵合法的樹。

?

題解

  • 我們假設k為最后取的樹,我們把一個葉子>=k染成1,把<k的染成0
  • 考慮一下樹形dp,設f[i][j][0/1]為以i為根的子樹中有j個1當前點為0/1的方案數
  • 那么對于當前是基層,也就是小A取值,f[i][j][0]= ∏f[son[x]][k][0],f[i][j][1]=。對于偶層,也就是小B取值也是一樣的
  • 枚舉前面兒子的葉子然后枚舉當前要合并的兒子的葉子背包一下
  • 我們可以枚舉k,也就是子樹中1的個數,所以我們最后要記入答案是∑(f[1][k][1]-f[1][k+1][1])k!?(size[1]-k)!

代碼

 1 #include <cstdio>
 2 #define ll long long
 3 using namespace std;
 4 const ll N=5010,mo=1e9+7;
 5 struct edge { int to,from; }e[N*2];
 6 ll f[N][N][2],head[N],size[N],jc[N],g[N],ans,n,cnt,r;
 7 void insert(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
 8 ll ksm(ll a,ll b){ for (r=1;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; return r;}
 9 ll C(ll x,ll y) { return jc[y]*ksm(jc[y-x],mo-2)%mo*ksm(jc[x],mo-2)%mo; }
10 void dfs(int d,int x,int y,int l,int r)
11 {
12     if (d>g[0]) { (f[x][r][l]+=y)%=mo; return; }
13     for (int i=0;i<=size[g[d]];i++) if (f[g[d]][i][l]) dfs(d+1,x,y*f[g[d]][i][l]%mo,l,r+i);
14 }
15 void dp(int x,int y,int k)
16 {
17     for (int i=head[x];i;i=e[i].from) if (e[i].to!=y) dp(e[i].to,x,k^1),size[x]+=size[e[i].to];
18     g[0]=0; for (int i=head[x];i;i=e[i].from) if (e[i].to!=y) g[++g[0]]=e[i].to;
19     if (size[x])
20     {
21         dfs(1,x,1,k,0);
22         for (int i=0;i<=size[x];i++) f[x][i][k^1]=(C(i,size[x])-f[x][i][k]+mo)%mo;
23     }
24     else size[x]++,f[x][0][0]=f[x][1][1]=1;
25 }
26 int main()
27 {
28     freopen("game.in","r",stdin),freopen("game.out","w",stdout),scanf("%lld",&n);
29     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
30     jc[0]=1; for (int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mo; dp(1,0,0);
31     for (int i=0;i<=size[1];i++) (ans+=f[1][i][1]*jc[i]%mo*jc[size[1]-i]%mo)%=mo;
32     printf("%lld",ans);
33 }

?

轉載于:https://www.cnblogs.com/Comfortable/p/10296073.html

總結

以上是生活随笔為你收集整理的[树形dp] Jzoj P5233 概率博弈的全部內容,希望文章能夠幫你解決所遇到的問題。

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