51Nod 1670 打怪兽

15 篇文章 0 订阅

基准时间限制:1 秒 空间限制:131072 KB 分值: 40  难度:4级算法题
 收藏
 关注
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
alpq654321  (题目提供者)


首先知道期望计算公式为: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;
}
      
      
     
     
    
    
   
   



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值