题目链接:http://codeforces.com/contest/499/problem/D
题意:有n首曲子,一首一首的放给你听,然后要你猜歌名,对于第i首歌,你前ti-1秒每一秒猜对概率为pi,在第ti秒你必猜对,一旦第i首歌被猜对,立刻播放下一首,求T秒之后你猜对歌曲数量的期望
思路:dp[i][j]表示第i首歌刚好在第j秒时被猜对
有转移dp[i][j] = ∑(dp[i-1][j-k]*p[i]^(k-1)*(1-p[i])(1<=k<=t[i]-1))+dp[i-1][j-t[i]]*p[i]^(t[i]-1)
暴力转移复杂度O(nT²),但求和部分可以前缀和优化,复杂度O(nT)
最后答案就是将所有的dp[i][j]加在一起,为什么是这样算的呢?因为你每转移一次就相当于多猜对一首歌,所以最后就是将所有的转移乘上发生这次转移的概率,即dp[i][j]
#include
#include
using namespace std;
double p[5005], dp[5005][5005];
int t[5005];
double Pow(double x, int k)
{
double ans = 1;
while(k)
{
if(k%2)
ans = ans*x;
x = x*x;
k /= 2;
}
return ans;
}
int main(void)
{
double now, ans, temp;
int n, T, i, j, k;
scanf("%d%d", &n, &T);
for(i=1;i<=n;i++)
{
scanf("%lf%d", &p[i], &t[i]);
p[i] /= 100;
}
dp[0][0] = 1, ans = 0;
for(i=1;i<=n;i++)
{
now = 0;
temp = Pow(1-p[i], t[i]-1);
for(j=1;j<=T;j++)
{
now *= 1-p[i];
now += dp[i-1][j-1]*p[i];
if(j>=t[i])
now -= dp[i-1][j-t[i]]*temp*p[i];
dp[i][j] = now;
if(j>=t[i])
dp[i][j] += dp[i-1][j-t[i]]*temp;
ans += dp[i][j];
}
}
printf("%.10f\n", ans);
return 0;
}