ACdream原创群赛(13)のwuyiqi退役专场 F:The Arrow (概率dp)

题目link:http://acdream.info/problem?pid=1113


小记:当时比赛晓得了是概率dp,但是头脑不清醒,没做。现在想来,当时的思路确实是对的


思路:解题报告的思路是:

dp[i] = dp[i+1]/6 + dp[i+2]/6 + dp[i+3] /6+...+ dp[i+6]/6 + 1

对特殊的几个,例:

dp[n-3] = dp[n-3]/2 + dp[n-2]/6 + dp[n-1]/6 + dp[n]/6 + 1;

即在n-3这个位置,有1/2的概率不变, 1/6的概率加1, 1/6的概率加2,1/6的概率加3, 相乘后得到平均期望 然后加上其投出的这一次 就是投出i的期望值

这个状态转移方程的最后结果即是 dp[0],  



我的思路是反过来的

dp[i] = dp[i-1]/6 + dp[i-2]/6 +...+ dp[i-6]/6 + 1

我觉得这样更符合人的思维些, 我当前这个i值,是有1/6从i-1过来的,1/6从i-2....等等

对于最开始时,如:

dp[3] = dp[3]/2 + dp[2]/6 + dp[1]/6 + dp[0]/6 + 1


解方程即是 左右乘以个 6, 然后计算是否有大于n 或小于0 的投掷,计算次数,用于计算结果


代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>

using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))
#define REP(a,b,c) for(int a = b; a < c; ++a)
#define eps 10e-8

const int MAX_ = 100010;
const int N = 100010;
const int INF = 0x7fffffff;

double d[MAX_];

int main(){
    //freopen("f:\\in.txt","r", stdin);
    //freopen("f:\\out.txt", "w", stdout);
	int T, n;
	scanf("%d", &T);
	while(T--){
	    mst(d, 0);
        scanf("%d", &n);
        d[0] = 0;
        REP(i, 1, n+1){
            int cnt = 0;
            REP(j, 1, 7){
                if(i - j >= 0){
                    d[i] += d[i-j];
                }
                else cnt++;
            }
            //printf("%d\n", cnt);
            d[i] += 6;
            d[i] /= (6-cnt);
        }
        printf("%.2f\n", d[n]);
	}
	return 0;
}


你可能感兴趣的:(ACdream原创群赛(13)のwuyiqi退役专场 F:The Arrow (概率dp))