1. 程式人生 > >[51nod1670] 打怪獸

[51nod1670] 打怪獸

div 開始 示例 const bool 增加 ace mod text

lyk在玩一個叫做“打怪獸”的遊戲。
遊戲的規則是這樣的。
lyk一開始會有一個初始的能量值。每次遇到一個怪獸,若lyk的能量值>=怪獸的能量值,那麽怪獸將會被打敗,lyk的能量值增加1,否則lyk死亡,遊戲結束。
若怪獸全部打完,遊戲也將會結束。
共有n個怪獸,由於lyk比較弱,它一開始只有0點能量值。
n個怪獸排列隨機,也就是說共有n!種可能,lyk想知道結束時它能量值的期望。
由於小數點比較麻煩,所以你只需要輸出期望*n!關於1000000007取模後的值就可以了!

例如有兩個怪獸,能量值分別為{0,1},那麽答案為2,因為遊戲結束時有兩種可能,lyk的能量值分別為0和2。期望為1,1*2!=2,所以答案為2。 Input
第一行一個數n(1<=n<=100000)。
接下來一行n個數ai表示怪獸的能量(0<=ai<n)。
Output
一行表示答案
Input示例
2
0 1
Output示例
2




可以發現一個性質,就是如果我們在第$i$局可以打第$j$個怪,那麽在第$i+1$局活著的話可以打第$j$個怪。
那麽我們設$f[i]$表示到第$i$輪還存活著的方案數。
顯然可以遞推$\large f[i] = f[i-1] \times \frac{sum[i-1]-i+1}{n-i+1}$.
$sum[i]$表示能量值小於等於$i$的怪的數量。
然後答案就是$\large \sum \left(f[i-1]-f[i] \right ) \times \left(i-1 \right)$。




#include <iostream>
#include 
<cstdio> #include <algorithm> #include <cstring> #include <bits/stdc++.h> using namespace std; #define reg register inline char gc() { static const int BS = 1 << 22; static unsigned char buf[BS], *st, *ed; if (st == ed) ed = buf + fread(st = buf, 1, BS, stdin);
return st == ed ? EOF : *st++; } #define gc getchar inline int read() { int res = 0;char ch=gc();bool fu=0; while(!isdigit(ch))fu|=(ch==-),ch=gc(); while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=gc(); return fu?-res:res; } #define mod 1000000007 #define ll long long int n; int sum[100005]; ll f[100005]; inline ll ksm(ll x, ll y) { ll res = 1; while(y) { if (y & 1) res = res * x % mod; x = x * x % mod; y >>= 1; } return res; } int ans; int main() { n = read(); for (reg int i = 1 ; i <= n ; i ++) sum[read()]++; for (reg int i = 1 ; i <= n ; i ++) sum[i] = sum[i - 1] + sum[i]; f[0] = 1; for (reg int i = 1 ; i <= n ; i ++) f[0] = f[0] * i % mod; for (reg int i = 1 ; i <= n ; i ++) f[i] = f[i - 1] * (sum[i - 1] - i + 1) % mod * ksm(n - i + 1, mod - 2) % mod; for (reg int i = 1 ; i <= n ; i ++) ans = (ans + (f[i - 1] - f[i]) * (i - 1)) % mod; cout << (ans + f[n] * n) % mod << endl; return 0; }

[51nod1670] 打怪獸