hdu4576 (概率dp+状态转移技巧)

题意: 机器人在一个有 n n 个格子的圆形上,初始在 1 1 号位,接下来给 m m 个指令,每个指令代表从当前格子向一个方向移动 x x 格,由于机器人方向感应有问题,所以会随机逆时针或顺时针移动 x x 格。问 m m 个指令后,落在 [ l , r ] [l,r] 的概率。
数据范围: 1 n 200 , 0 m 1 0 6 1\leq n\leq 200,0\leq m\leq 10^6

题解: f [ n o w ] [ i ] f[now][i] 表示当前执行了 n o w now 个指令,到达了第 i i 格的概率,初始化为 f [ 0 ] [ 1 ] = 1 f[0][1]=1
由于 n m nm 1 0 8 10^8 级别,故空间爆炸,考虑执行第 n o w now 个指令只与执行到了 n o w 1 now-1 个指令有关,所以可以模 2 2 来更新状态,最后为 0 / 1 0/1 则统计 f [ 0 / 1 ] [ l , r ] f[0/1][l,r] 的概率即可。

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<iostream>
using namespace std;
int n, m, l, r;
const int N = 210;

inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
	while(isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
	return x * f; 
}

double f[2][N]; //两个状态是为了区分上一个状态和当前状态 
int main()
{
	while(true) {
		n = read(), m = read(), l = read(), r = read(); 
		if(!(n || m || l || r)) break;
		--l, --r;
		for(int i = 1; i < n; i++) f[1][i] = 0; 
		f[1][0] = 1;
		int now = 1;
		for(int i = 1; i <= m; i++) {
			int step = read();
			for(int j = 0; j < n; j++) {
				f[now ^ 1][j] = f[now][(j - step + n) % n] * 0.5 + f[now][(j + step) % n] * 0.5;
			} 
			now ^= 1;
		}
		double res = 0;
		for(int i = l; i <= r; i++) res += f[now][i];
		printf("%.4lf\n", res);
	}
}

注意: 本题很卡时间,建议快读。

猜你喜欢

转载自blog.csdn.net/weixin_43900869/article/details/107641156