【期望】飞行棋

D e s c r i p t i o n Description Description

牛牛在玩飞行棋。

有无限个格子排成一行,从左到右,标号为 0,1,…,n,…,终点为 0,有一架飞机一开始在 n 号位置。

排骨龙每回合可以先投掷一次 d 面的骰子,1 到 d 等概率出现。

1.投出点数 x 后,飞机会移动 x 步,每步移动一格,方向初始向左移动,若到达终点,会向右移动。
2.若投出的点数为 d 点,可以继续投掷,直到投出的点数不是 d 点。

求让这架飞机停在终点回合数的期望。

I n p u t Input Input

第一行一个数字 T 表示 T(T ≤ 100) 组数据。

接下来每行两个正整数 n,d(2 ≤ d, n ≤ 100000)

对于 20% 数据,2 ≤ n, d <=15
对于 50% 数据,2 ≤ n, d ≤ 150
对于 100% 数据,2 ≤ n, d ≤ 100000

O u t p u t Output Output

输出 T 行,每行保留两位小数输出答案。

S a m p l e Sample Sample I n p u t Input Input
6
1 6
2 6
3 6
4 6
5 6
6 6
S a m p l e Sample Sample O u t p u t Output Output
5.00
5.00
5.00
5.00
5.00
5.17

T r a i n Train Train o f of of T h o u g h t Thought Thought

先分类讨论
当 n < d 时与当 n >= d
当 n < d 时,那么你丢出的筛子就有d种可能
但是因为当丢到d时重丢
所以实际上是只有d - 1种可能
因为只要丢到某一个数恰好走到0
否则就要继续丢
所以设ans步到终点,则

解得ans = d - 1
然后当n >= d的时候
就直接DP

但是O(Tnd)它炸了
所以得优化
把左边部分化简,用前缀和来算,就是

嗯可以了
这个是优化前(50分

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

double F[100250];
int T, n, d;

int main()
{
    
    
	scanf("%d", &T);
	while(T--)
	{
    
    
		memset(F, 0, sizeof(F));
		scanf("%d%d", &n, &d);
		if(n < d)
		{
    
    
			printf("%d.00\n", d - 1);
			continue;
		}
		
		F[0] = 1;//为了方便计算
		
		for(int k = 1; k < d; ++k)
			F[k] = d - 1;
			
		for(int k = d; k <= n; ++k)
		{
    
    
			for(int i = k - d + 1; i < k; i++)
				F[k] += (F[i] + 1) / (d * 1.0);
			F[k] += F[k - d] / (d * 1.0);
		}
		printf("%.2lf\n", F[n]);
	}
	return 0;
}

优化后(满分

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

double F[100250], Sum[100250];
int T, n, d;

int main()
{
    
    
	scanf("%d", &T);
	while(T--)
	{
    
    
		memset(F, 0, sizeof(F));
		memset(Sum, 0, sizeof(Sum));
		scanf("%d%d", &n, &d);
		if(n < d)
		{
    
    
			printf("%d.00\n", d - 1);
			continue;
		}
		F[0] = Sum[0] = 1;//方便计算
		
		for(int i = 1; i < d; ++i)
			F[i] = d - 1, Sum[i] = Sum[i - 1] + F[i];
		for(int i = d; i <= n; ++i)
		{
    
    
			F[i] = (Sum[i - 1] - Sum[i - d] + d - 1) / (d * 1.0);
			F[i] += F[i - d] / (d * 1.0);
			Sum[i] = Sum[i - 1] + F[i];
		}
		printf("%.2lf\n", F[n]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SSL_wujiajie/article/details/109436610