题目:http://acm.timus.ru/problem.aspx?space=1&num=1776
Denis has to prepare the Ural State University 90th anniversary firework. He bought n rockets and started to think of the way he should launch them. After a pair of sleepless nights he invented the following algorithm.
All n rockets are placed on the surface in a single line. The interval between two consecutive salvos is ten seconds. The leftmost and the rightmost rocket are launched in the first salvo. After i salvos are fired, all non-empty segments between two neighboring launched rockets are considered. One rocket is chosen randomly and uniformly at each of these segments. All chosen rockets are launched in the (i + 1)-st salvo. Algorithm runs until all rockets are launched.
Calculate the average duration in seconds of such a firework.
Input
The only input line contains an integer n (3 ≤ n ≤ 400), which is the number of rockets bought by Denis.
Output
Output the expected duration of the firework in seconds, with absolute or relative error not exceeding 10−6.
Sample
input | output |
---|---|
5 | 26.66666666666 |
Notes
First, the rockets with numbers 1 and 5 are launched. 10 seconds later the rocket 3 is launched with probability 1/3; in that case, 10 more seconds later the rockets 2 and 4 are launched, and the firework is over after 20 seconds. In case the rocket 2 or rocket 4 is launched in the second salvo (this happens with probability 2/3), the firework is over after 30 seconds.
思路:
概率dp。
dp[i][j]表示点燃i个火箭需要j个10秒时间的概率。
sum[i][j]表示点燃i个火箭需要小于等于j个10秒时间的概率。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 450;
double dp[MAXN][MAXN];
double sum[MAXN][MAXN];
int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
n -= 2;
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
dp[0][0] = 1.0;
for (int i = 0; i <= n; i++)
{
sum[0][i] = 1.0;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= i; j++)
{
int l = j - 1;
int r = i - j;
int temp = max(l, r) + 1;
for (int k = 1; k <= temp; k++)
{
dp[i][k] += (dp[l][k-1] * sum[r][k-1] + sum[l][k-1] * dp[r][k-1]
- dp[l][k-1] * dp[r][k-1]) / i;
}
}
for (int j = 1; j <= n; j++)
{
sum[i][j] = sum[i][j-1] + dp[i][j];
}
}
double ans=0;
for (int i = 1; i <= n; i++)
{
ans += dp[n][i] * i;
}
printf("%.10lf\n", ans * 10.0);
}
return 0;
}