链接:https://ac.nowcoder.com/acm/contest/549/C
来源:牛客网
小A最近开始沉迷买彩票,并且希望能够通过买彩票发家致富。已知购买一张彩票需要3元,而彩票中奖的金额分别为1,2,3,4元,并且比较独特的是这个彩票中奖的各种金额都是等可能的。现在小A连续购买了n张彩票,他希望你能够告诉他至少能够不亏本的概率是多少。
输入描述:
一行一个整数N,为小A购买的彩票数量一行一个整数N,为小A购买的彩票数量
输出描述:
输出一个最简分数a/b,表示小A不亏本的概率。若概率为1,则输出1/1,概率为0,则输出0/1。输出一个最简分数a/b,表示小A不亏本的概率。若概率为1,则输出1/1,概率为0,则输出0/1。
示例1
输入
2
输出
3/8
备注:
0≤n≤30
一开始看到这种求概率的题,我都是傻傻的推公式,也不是不能推,只是会比较麻烦,而且不能被条件搞混淆,我推不出来。
不过大部分人用的办法都是找前后两项的关系。
也就是思考买i张彩票不亏本的概率,与买i-1张彩票不亏本的概率是否有关系。
很明显的是,有关系的。假设目前已经买了3张彩票,我现在要买第四张。
第四张购买赚钱有四种情况(每张都有的四种情况) -2元 -1元 0元 1元
例如,如果第四张买了个 -2元(中奖1元),那么这种情况下想要不亏,就必须前面三张要至少赚 2 元。
同理,买了-1元,前面三张必须至少赚 1 元。
这也就说明,后面购买的盈亏情况可以直接有前面几张的情况得到,状态转移方程如下:
dp[i][j] 代表第 i 张彩票赚了 j 元的可能情况数。
dp[i][j]=dp[i-1][j-1]+dp[i-1][j]+dp[i-1][j+1]+dp[i-1][j+2]
输入的数字为n 只需要记录第n层所有不亏的种类数。代码如下
#include<stdio.h>
#include<iostream>
using namespace std;
typedef unsigned long long ll;
ll dp[35][200]={0};
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
int main(){
int n;
cin>>n;
const int ze=100; //定义一个0点,小于0点的位置说明亏损。
dp[0][ze]=1;
dp[1][ze]=1;
dp[1][ze-1]=1;
dp[1][ze-2]=1;
dp[1][ze+1]=1;
int i,j;
for(i=2;i<=n;i++)
for(j=ze-(n*2);j<=ze+n;j++){
for(int k=j-1;k<=j+2;k++)
dp[i][j]=dp[i][j]+dp[i-1][k];
}
ll sum=0;
for(i=ze;i<=ze+n;i++)
sum=sum+dp[n][i];
ll s2=ll(1<<n)*ll(1<<n); // s2代表分母,这里是4^n
ll g=gcd(sum,s2);
printf("%lld/%lld\n",sum/g,s2/g);
return 0;
}