lyk在玩一个叫做“打怪兽”的游戏。
游戏的规则是这样的。
lyk一开始会有一个初始的能量值。每次遇到一个怪兽,若lyk的能量值>=怪兽的能量值,那么怪兽将会被打败,lyk的能量值增加1,否则lyk死亡,游戏结束。
若怪兽全部打完,游戏也将会结束。
共有n个怪兽,由于lyk比较弱,它一开始只有0点能量值。
n个怪兽排列随机,也就是说共有n!种可能,lyk想知道结束时它能量值的期望。
由于小数点比较麻烦,所以你只需要输出期望*n!关于1000000007取模后的值就可以了!
游戏的规则是这样的。
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
首先知道期望计算公式为:E=∑p[i]*i; (i表示游戏结束时能量,p[i]表示游戏结束时能量为i的概率)
而 p[i]*n! 表示游戏结束时能量为i的方案数,所以用排列组合计算达到能量为i时的方案数即可
官方题解:本题的关键点是发现如果我能在第i轮打败怪物j,那么我一定能在第i+1轮打败怪物j(前提是我还活着)。
因此我们可以通过递推来做这题。
令dp[i]表示第i轮我仍然存活时的方案综述,这里lyk的能量也必然为i。
显然dp[0]=n!。因为不管怎么排列,第0轮总是能存活的。
找到那些可以打败的怪物数量x,其中这些怪物已经被打败i个。
此时第i+1轮我仍然能存活的概率为(x-i)/(n-i),只要将这个概率乘上dp[i]就能知道dp[i+1]的值。
这里除法可以用逆元来处理。时间复杂度为线性。
还不明白接着看:
模拟打怪兽的过程,设当前能量为energy,能量达到energy时的方案数为way(way == 上面讲的dp[energy]),不能打过的怪兽共rem只,则还剩余n-energy只怪兽未打,有两种情况:
①打一只不能打过的怪兽,则游戏结束,则结束时能量值为energy的方案数共:way*rem*(n-energy-1)!
②打一只能打过的怪兽,则游戏继续,能量值达到energy+1时的方案数为way*(n-energy-rem)
#include
#include
#include
#include
#define MAXN 100005
#define Mod 1000000007
using namespace std;
typedef long long LL;
LL num[MAXN],dp[MAXN];
LL Fast_Pow(LL a,LL b) {
LL ret = 1;
while(b) {
if (b & 1) ret = ( ret * a ) % Mod;
a = ( a * a ) % Mod, b >>= 1;
}
return ret;
}
int main(int argc,char *argv[]) {
int n; scanf("%d",&n); LL temp;
dp[0] = 1;
for(int i=1; i<=n; ++i) dp[0] = (dp[0] * i) % Mod;
for(int i=1; i<=n; ++i){
scanf("%lld",&temp);
num[temp]++;
}
for(int i=1; i<=n; ++i) num[i] += num[i - 1];
for(int i=0; i<=n; ++i) {// 击败i个
LL Inv = Fast_Pow(n - i,Mod - 2) % Mod;
dp[i + 1] = ((dp[i] * (num[i] - i)) % Mod) * Inv % Mod;
}
LL Ans = 0;
for(int i=1; i<=n; ++i) {
LL s = (dp[i-1] - dp[i] + Mod) % Mod;//dp[i-1] - dp[i] 第i-1轮的时候活着的方案数-第i轮活着的
//方案数 == 就是第i轮死了的情况
Ans = (Ans + s * (i-1) % Mod) % Mod;
}
Ans = (Ans + (dp[n] * n) % Mod) % Mod;//所有的怪兽都打过了
printf("%lld\n",Ans);
return 0;
}