您的位置:首页 > 其它

51Nod-1670-打怪兽

2016-10-01 13:38 246 查看
ACM模版

描述



题解

一道十分不错的dp,越发的感觉我的dp好垃圾啊~~~关键是递推思维。

官方题解:

本题的关键点是发现如果我能在第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]的值。

这里除法可以用逆元来处理。

时间复杂度为线性。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

typedef long long ll;

const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 5;

int n;
ll dp[MAXN];
int a[MAXN];

void init()
{
ll res = 1;
for (int i = 1; i <= n; i++)
{
res = (res * i) % MOD;
}
dp[0] = res;
}

ll exp_mod(ll a, ll b)
{
ll res = 1;
while (b != 0)
{
if (b & 1)
{
res = (res * a) % MOD;
}
a = (a * a) % MOD;
b >>= 1;
}
return res;
}

void input()
{
int i, temp;
scanf("%d", &n);

for (i = 1; i <= n; i++)
{
scanf("%d", &temp);
a[temp]++;
}
}

void solve()
{
int i;
ll res = 0;
for (i = 1; i <= n; i++)
{
a[i] = a[i] + a[i - 1];
}
for (i = 0; i <= n; i++)
{
//  已经击败i个
ll t = exp_mod(n - i, MOD - 2) % MOD;   //  求逆元
dp[i + 1] = ((dp[i] * (a[i] - i)) % MOD) * t % MOD;
}
for (i = 1; i <= n; i++)
{
ll s = (dp[i - 1] - dp[i] + MOD) % MOD; //  在第i轮被击败的情况
res = (res + s * (i - 1) % MOD) % MOD;
}
res = (res + (dp
* n) % MOD) % MOD;
cout << res;
}

int main()
{
input();
init();

solve();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  难题 dp