小a和小b在玩遊戲。這個遊戲是這樣的:
有一棵n個點的以1為根的有根樹,葉子有權值。假設有m個葉子,那麼樹上每個葉子的權值序列就是乙個1->m 的排列。
一開始在1號點有一顆棋子。兩人輪流將這顆棋子移向其當前位置的乙個兒子。假如棋子到達葉子,遊戲結束,最終獲得的權值為所在葉子對應權值。
小a希望最後的權值盡量大,小b希望盡量小。小a是先手。
在玩了很多局遊戲後,小b對其中絕大多數局遊戲的結果不滿意,他覺得是小a對葉子權值做了手腳。於是他一怒之下,決定將葉子的權值隨機排列。現在小b想知道,假如葉子的權值是隨機排列的(即葉子權值的每種排列都以等概率出現),那麼遊戲期望的結果是多少?
請輸出答案乘上m! 對10^9+7取模的結果,顯然這是乙個整數。
這題有乙個很套路的想法,就是我們考慮最後答案大於等於k的方案數,然後用k的方案數-k+1的方案數就是等於k的方案數。
那麼大於等於k的方案數的討論也有乙個很套路的想法,就是對於所有大於等於k的權值設為1,其它設為0,然後向上合併,如果最後在根節點能合併出1,那麼這種01染色方案就合法,然後再給0和1表上號就好了(0的個數的階乘和1的個數的階乘)
那麼我們就設f[i][j][0,1]表示在第i個點,以它為根的子樹的葉子節點填了j個0,當前這個點的顏色為0或1。
然後我們分層數來考慮,對於奇數層(從0層開始),那麼它的兒子數有乙個0,當前顏色就是0的,那麼我們就用總方案-全都是1的個數來求,當前要是1的話,那麼就把兒子的1做個揹包,列舉前面兒子的葉子然後列舉當前要合併的兒子的葉子揹包一下(這樣是n^2的,相當於把所有的葉子兩兩之間匹配一下),對於偶數層也是一樣的。
最後在根節點上恰好為k的方案,然後再標號就好了。
其實還有一種求答案的方法,我們要求的期望是∑x
∗p(x
) 那麼其實在乙個平面圖上就相當於1p(1),2p(2),3p(3),…np(n),上面的方法是豎著求的,那麼我們考慮橫著求,設p′
(x) 表示權值大於等於x的概率,那麼答案就是∑p
′(x)
和我們上面設的狀態是一樣的。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int maxn=5007,mo=1e9+7;
ll i,j,k,l,t,n,m;
ll first[maxn*2],last[maxn*2],next[maxn*2],num,pp;
ll ni[maxn],fact[maxn],ans,f[maxn][maxn][2],son[maxn];
void add(int
x,int
y)ll qsm(ll x,ll y)
ll c(ll x,ll y)
void dfs(int
x,int
y,int z)
if(z%2)f[x][k][1]=pp;else f[x][k][0]=pp;
if(l==1)
}son[x]+=son[last[i]];}}
if(!l)son[x]=1,f[x][0][1]=f[x][1][0]=1;
else
}int main()
ans=(ans+mo)%mo;
printf("%lld\n",ans);
}
JZOJ5242 GDOI模擬 矩陣
給出乙個n m 的01 矩陣,求其中有多少個連續子矩陣,使得其面積大於等於k,且其中不包含1。非常經典的一道題目。首先我們很容易知道n 3的方法。那麼我們來優化一下。我們先求出f i j 表示從 i,j 向右連續1的數量。然後把這些從大到小的插入 桶排一下 然後如果上面或下面已經有了就合併,然後算出...
JZOJ5242 GDOI2018模擬8 8 矩陣
description 給出乙個n m 的01 矩陣,求其中有多少個連續子矩陣,使得其面積大於等於k,且其中不包含1。input 第一行為用空格隔開的三個整數n,m,k。分別表示矩陣的行數,列數和子矩陣的最小面積。接下來的n 行每行為用空格隔開的m 個整數,為題目中給出的矩陣。output 輸出一行...
JZOJ3400 GDOI2014模擬 旅行
給你乙個圖,讓你選擇權值和最小的邊,使得 1 和 n 2 和 n 1 k 和 n k 1 聯通。k leq 4 一看到這題就覺得特別神仙 然後去思考網路流 搞出了乙個最小割,後來發現這是錯的 匆匆打了個表,獲得了這題的十分之一的分數。其實這題有水法,許多人是全排列 spfa 跑了一遍之後將路過的邊清...