標籤:des style blog http color io for ar
hdu4921 Map(狀壓統計)
題意:有10條長度不超過1000鏈,鏈上的節點有權值。我們從這些節點中選出一些節點來,若要選節點u,則u的前繼都得被選進去。對於某一種選定的情況,我們能獲得的權值為,選定的節點的權值和,以及一些附加值。附加值的求法為,對於每條鏈的同一深度的點,若選定的點的個數超過1,那麼會得到的附加值為(si*xi/ci),其中si表示該層選中的點的權值和,xi為該層選中的點的個數,ci為該層的總點數。問,對於所有的選擇情況,能得到的權值期望會是多少?
解法:很直觀的一點,期望值=所有情況的權值和/所有的情況數。情況數很好算,所有的鏈長+1求乘積即可(要減去什麼都不選的一種情況)。而所有的情況的權值和,我們這樣算:因為同一層之間的點,選的個數會對該層產生一個影響,所以我們一層一層考慮。總共只有10條鏈,故考慮任何一層上的點,選或者不選的狀態只有2^10種,那麼我們枚舉這2^10個狀態,對於某一個狀態,我們可以暴力算出能得到的點權和以及附加值,但是對於這個狀態,它會出現在很多種選擇情況當中。比如我們有兩條鏈,鏈長都是3,當前考慮的是第二層的10狀態(二進位1表示選,0表示不選),那麼,當鏈1分別取前2個,前3個,鏈2分別取前0個,前1個。這四種都會包含第二層10的狀態,因此,這個狀態會在4種選擇情況中貢獻給權值總和,故而要將求出的點權和+附加值乘上情況數再累加到權值總和當中,每一層都考慮完了之後,問題得解。
代碼:
#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>using namespace std ;int son[11111] ;int chain[10][1111] , a[11111] ;int vis[11111] , du[11111] , len[11] ;double dfs ( int u , int step , int c ) { chain[c][step] = a[u] ; if ( son[u] == -1 ) return step + 2 ; return dfs ( son[u] , step + 1 , c ) ;}int main () { int n , m ; int T ; scanf ( "%d" , &T ) ; while ( T -- ) { scanf ( "%d%d" , &n , &m ) ; memset ( chain , 0 , sizeof ( chain ) ) ; memset ( du , 0 , sizeof ( du ) ) ; memset ( son , -1 , sizeof ( son ) ) ; for ( int i = 0 ; i < n ; i ++ ) scanf ( "%d" , &a[i] ) ; for ( int i = 1 ; i <= m ; i ++ ) { int a , b ; scanf ( "%d%d" , &a , &b ) ; son[a] = b ; du[b] ++ ; } double sum = 1 , ans = 0 ; int tot = 0 ; for ( int i = 0 ; i < n ; i ++ ) { if ( du[i] == 0 ) { len[tot] = dfs ( i , 0 , tot ) ; sum *= len[tot] ; len[tot] -- ; tot ++ ; } } sum -= 1 ; // printf ( "sum = %f\n" , sum ) ; for ( int i = 0 ; i < 1000 ; i ++ ) { for ( int j = 0 ; j < 1 << tot ; j ++ ) { int flag = 0 ; double add = 0 , p = 1 , x = 0 , cnt = 0 ; for ( int k = 0 ; k < tot ; k ++ ) { if ( chain[k][i] ) cnt ++ ; if ( j & (1<<k) ) { if ( chain[k][i] == 0 ) { flag = 1 ; break ; } add += chain[k][i] ; x ++ ; p *= len[k] - i ; } else { p *= min ( len[k] + 1 , i + 1 ) ; } } if ( flag ) continue ; double fuck = ( add + (x>1?(add*x/cnt):0) ) * p ; // printf ( "i = %d , j = %d , fuck = %f\n" , i , j , fuck ) ; // printf ( "add = %lf , p = %lf , x = %lf , cnt = %lf\n" , add , p , x , cnt ) ; ans += fuck ; } } printf ( "%.3f\n" , ans / sum ) ; } return 0 ;}