Discovering Gold LightOJ - 1030[概率dp或者记忆化搜索]


题目大意:有一个 [ 1 , n ] [1,n] [1,n]的数轴,数轴上的每个对应位置上都有金矿,你初始位置是1,然后你每次都会投色子决定你下一步跳到哪里,如果你跳出了 n n n,那么你就要重新投。问你跳到 n n n的时候期望搜集到的金矿是多少?


很明显的概率dp,我们设 d p [ i ] dp[i] dp[i]为从i跳到n的得到期望金矿,那么很明显 d p [ n ] = a [ n ] dp[n] = a[n] dp[n]=a[n]我们就可以逆推回去 d p [ j ] = ∑ k = j + 1 m i n ( j + 6 , n ) d p [ k ] dp[j]=\sum_{k=j+1}^{min(j+6,n)}dp[k] dp[j]=k=j+1min(j+6,n)dp[k]双重循环 O ( 6 ∗ n ) O(6*n) O(6n)


下面是记忆化搜索的写法

#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1) 
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define vector Vector
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 1e7+10, mod = 1e9 + 7;
const double eps = 0.005;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) 
{
    read(first);
    read(args...);
}
int T, n;
int a[110];
double f[110];
double dp(int x)
{
    if(x == n) return f[n] = a[n];
    if(f[x]) return f[x];
    int sum = min(n - x,6);
    double &v = f[x]; v = a[x];
    _for(i,1,sum+1)
      v += dp(x+i)/(double)sum;
    return v;
}

int main()
{
    read(T);
    int C = 1;
    while(T --)
    {
        ms(f,0);
        read(n);
        _for(i,1,n+1) read(a[i]);
        printf("Case %d: %lf\n",C++,dp(1));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值