【HDU】4418 Time travel

http://acm.hdu.edu.cn/showproblem.php?pid=4418

题意:一个0~n-1的坐标轴,给出起点X、终点Y,和初始方向D(0表示从左向右、1表示从右向左,-1表示起点或终点),在走的过程中如果到达起点或终点,那么下一步往反方向走。每次可以走1~m步,每步概率为p[i],问走到终点的期望步数。(n,m,X,Y<=100)

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=205;
const double eps=1e-6;
double A[N][N], p[N], C;
inline double abs(double x) { return x<0?-x:x; }

int guass(int n, int m) {
	int x=1, y=1;
	while(x<=n && y<=m) {
		int pos=x;
		for(int i=x+1; i<=n; ++i) if(abs(A[i][y])>abs(A[pos][y])) pos=i;
		if(abs(A[pos][y])<eps) { ++y; continue; }
		for(int i=1; i<=m+1; ++i) swap(A[x][i], A[pos][i]);
		for(int i=x+1; i<=n; ++i) if(abs(A[i][y])>=eps) {
			double t=A[i][y]/A[x][y];
			for(int j=y; j<=m+1; ++j) A[i][j]-=t*A[x][j];
		}
		++x; ++y;
	}
	for(int i=x; i<=n; ++i) if(abs(A[i][m+1])>=eps) return 0;
	for(int i=m; i; --i) if(abs(A[i][i])>=eps) {
		for(int j=i+1; j<=m; ++j) A[i][m+1]-=A[j][m+1]*A[i][j];
		A[i][m+1]/=A[i][i];
	}
	return 1;
}
bool vis[N];
int n, m, X, Y, D, all;
void get(int now, double a[]) {
	if(!vis[now]) { a[now]=1; return; }
	int fx=1, x=now;
	if(x>n) fx=-1;
	for(int i=1; i<=m; ++i) {
		if(x==n) { fx=-1; x=all; }
		else if(x==n+1) { fx=1; x=1; }
		x+=fx;
		a[x]+=p[i];
	}
	a[now]-=1;
	a[all+1]=-C;
}
void bfs() {
	static int q[N], front, tail, x, fx;
	memset(vis, 0, sizeof(bool)*(all+1));
	front=tail=0; q[tail++]=X+D*n;
	while(front!=tail) {
		x=q[front++]; if(front==N) front=0;
		fx=1;
		if(x>n) fx=-1;
		for(int i=1; i<=m; ++i) {
			if(x==n) { fx=-1; x=all; }
			else if(x==n+1) { fx=1; x=1; }
			x+=fx;
			if(!vis[x] && abs(p[i])>=eps) { vis[x]=1; q[tail++]=x; if(tail==N) tail=0; }
		}
	}
	vis[1]=vis[all]=vis[Y]=vis[Y+n]=0;
}
int main() {
	int T; scanf("%d", &T);
	while(T--) {
		scanf("%d%d%d%d%d", &n, &m, &Y, &X, &D); ++X; ++Y;
		C=0;
		for(int i=1; i<=m; ++i) scanf("%lf", &p[i]), p[i]/=100, C+=p[i]*i;
		if(X==Y) { puts("0.00"); continue; }
		if(D==-1) { if(X==1) D=1; else D=0; }
		all=n<<1;
		bfs();
		for(int i=1; i<=all; ++i) { memset(A[i], 0, sizeof(double)*(all+2)); get(i, A[i]); }
		if(guass(all, all)) {
			if(abs(A[X+D*n][all+1])<eps) puts("Impossible !");
			else printf("%.2f\n", A[X+D*n][all+1]);
		}
		else puts("Impossible !");
	}
	return 0;
}

  

这题我是调得憔悴啊QAQ

1、首先一开始我并没有想到有非法状态(即转移不到的状态我照样让他进了高斯中的矩阵中QAQ)

2、D=-1的条件漏看了啊,导致我sb的提交了20+次然后每次都是RE QAQ 妈妈呀...

首先方程和高斯消元比较显然..

设$d[i]$表示从$i$走到达终点所需要的步数:

$$d[i]=\sum_{k=1}^{m} p[k](d[转移到k步后]+k)$$

变换一下变成:

$$\sum_{k=1}^{m} p[k]d[转移到k步后] - d[i] = -\sum_{k=1}^{m} p[k]*k$$

发现这和方向其实是有关的,那么我们可以变成两个状态:

$1<=i<=n$,$d[i]$表示从左向右,$d[i+n]$表示从右向左。判断一些非法状态即可

可是这样是有问题的,在某些情况下可能某个$i$没有合法被访问过,那么就要bfs一次....(因为概率为0的时候是不会访问的啊QAQ所以不要放入合法状态中...)

(至此概率期望dp完结撒花(咦为什么我做了12天才搞完?(妈妈呀,这效率太低了啊.

时间: 2024-10-06 07:21:49

【HDU】4418 Time travel的相关文章

【HDOJ】4418 Time travel

1. 题目描述K沿着$0,1,2,\cdots,n-1,n-2,n-3,\cdots,1,$的循环节不断地访问$[0, n-1]$个时光结点.某时刻,时光机故障,这导致K必须持续访问时间结点.故障发生在结点x处,方向为d,在访问k个结点后时光机以概率$P_k%$的概率修复好,k不超过m.求当K最终访问结点Y时经过的时光结点的期望. 2. 基本思路上述循环节包含包含$nn = 2n-2个$元素(因此,尤其需要特判n=1的情况,否则除0wa).通过x和方向d可以唯一的确定x在这个循环节中的位置.设$

【HDU】2147 kiki&#39;s game

http://acm.hdu.edu.cn/showproblem.php?pid=2147 题意:n×m的棋盘,每次可以向左走.向下走.向左下走,初始在(1, m),n,m<=2000,问先手是否胜利. #include <cstdio> using namespace std; int main() { int n, m; while(scanf("%d%d", &n, &m), n|m) (n&1)&&(m&1)?

【HDU】4923 Room and Moor(2014多校第六场1003)

Room and Moor Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 263    Accepted Submission(s): 73 Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0

【HDU】4888 Redraw Beautiful Drawings 网络流【推断解是否唯一】

传送门:pid=4888">[HDU]4888 Redraw Beautiful Drawings 题目分析: 比赛的时候看出是个网络流,可是没有敲出来.各种反面样例推倒自己(究其原因是不愿意写暴力推断的).. 首先是简单的行列建边.源点向行建边.容量为该行元素和,汇点和列建边.容量为该列元素和.全部的行向全部的列建边,容量为K. 跑一次最大流.满流则有解,否则无解. 接下来是推断解是否唯一. 这个题解压根没看懂.还是暴力大法好. 最简单的思想就是枚举在一个矩形的四个端点.设A.D为主对角

【HDU】4918 Query on the subtree 点分治+树状数组

传送门:[HDU]4918 Query on the subtree 题目分析: 首先,简化问题. 1.求一次到点u的距离不超过d的点的个数.很容易,一次O(NlogN)的点分治便可以完成. 2.多次进行操作1.此时不能每次都O(NlogN)了,太慢了.我们考虑到对于点分治,树的重心一共有logN层,第一层为整棵树的重心,第二层为第一层重心的子树的重心,以此类推,每次至少分成两个大小差不多的子树,所以一共有logN层.而且,对于一个点,他最多只属于logN个子树,也就是最多只属于logN个重心.

【HDU】1754 I hate it ——线段树 单点更新 区间最值

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 37448    Accepted Submission(s): 14816 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要

【HDU】 1160 FatMouse&#39;s Speed (DP)

一开始写的dfs进行记忆化结果不知道怎么进行路径的记录...改成循环就好了 dp[i] = max(dp[j]) + 1 , weight[j] < weight[j] && speed[j] > speed[i] 一开始进行一次排序使得重量递增,这样只需要考虑速度就好了 #include<cstdio> #include<algorithm> using namespace std; const int maxn = 10005; struct Mou

【hdu】Mayor&#39;s posters(线段树区间问题)

需要离散化处理,线段树的区间修改问题. 需要注意的就是离散化的时候,由于给的数字是一段单位长度,所以需要特殊处理(因为线段的覆盖和点的覆盖是不一样的) 比如:(1,10)(1,4) (6,10) 离散化之后是 1 , 4 , 6 , 10 分别离散为 1 2 3 4 覆盖的时候先覆盖1 4 之后覆盖了1 2 之后覆盖了 2 3,结果为2 但是实际上应该是3 13450359 201301052100 2528 Accepted 1140K 985MS C++ 1960B 2014-09-17 1

【HDU】4908 (杭电 BC #3 1002题)BestCoder Sequence ——哈希

BestCoder Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 573    Accepted Submission(s): 201 Problem Description Mr Potato is a coder.Mr Potato is the BestCoder. One night, an amazing s