【2020牛客NOIP赛前集训营-普及组】飞行棋

题目

题目链接:https://ac.nowcoder.com/acm/contest/7612/D

思路

显然要棋子在 ([1,d))([d,n]) 的时候分开做。
当棋子在 ([1,d)) 的时候,假设现在在位置 (p),骰子扔到的是 (x) 点,那么棋子可能会变到 (p-x)(x-p) 的位置。
发现只有当 (x) 恰好等于 (p) 的时候才可以结束,否则 (p) 将变为依然在 ([1,d)) 中的另一个位置 (p')。那么其实等价于在 (1sim d-1) 中一直随机一个数,直到随机到 (1) 时停止,求期望次数。
设期望 (s) 次扔到点 (1),那么有

[s=frac{d-2}{d-1}(s+1)+frac{1}{d-1} ]

解方程得到 (s=d-1)
那么当棋子在 ([1,d)) 时,期望 (d-1) 次才会回到点 (0)
那么当棋子所在位置 (pgeq d) 时,由于只会不停往左走,所以可以设 (f[i]) 表示点 (i) 开始期望多少次可以回到点 (0),这样是没有后效性的。
时间复杂度 (O(Tn))

代码

#include <bits/stdc++.h>
using namespace std;

const int N=100010;
int Q,n,d;
double f[N],sum[N];

int main()
{
	scanf("%d",&Q);
	while (Q--)
	{
		scanf("%d%d",&n,&d);
		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+f[i-d]/d;
			sum[i]=sum[i-1]+f[i];
		}
		printf("%.2lf
",f[n]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/13890102.html