传送门:牛客
题目描述:
小A最近开始沉迷买彩票,并且希望能够通过买彩票发家致富。已知购买一张彩票需要3元,而彩票中奖的金额分别为
1,2,3,4元,并且比较独特的是这个彩票中奖的各种金额都是等可能的。现在小A连续购买了n张彩票,他希望你能够告
诉他至少能够不亏本的概率是多少。
输入:
2
输出:
3/8
一道线性dp题
主要思路:
- 观察这道题,我们能有一个比较显然的想法,我们可以使用
dp[i][j]
来记录买了第i
张彩票赚了j
块钱的次数(注意,是次数).那么显然的我们的最终答案就应该是
ll ans=0;ll ans2=0;
for(int i=n;i<=4*n;i++) {
ans+=dp[n][i];
if(i>=3*n) {
ans2+=dp[n][i];
}
}
ANS=ans/ans2
因为我们的ans记录的是所有的金额的次数,而我们的ans2记录的是所有的不亏钱的金额的次数
- 接下来需要做的就是如何推出这个转移关系了,其实这个转移方程也十分的简单,假设我们现在枚举到的金额为
j
,那么显然的我们可以由之前的j-1
,j-2
,j-3
,j-4
转移过来,因为彩票一次只能增加[1,4]
,当然我们的j
减去1,2,3,4之后应该大于我们的i-1
,因为前i-1
张彩票至少是可以赚i-1
块钱的.
最后总结一下我们的dp方程
dp[i][j]+=(dp[i-1][j-k]) k ∈ \in ∈ [ 1 , 4 ] [1,4] [1,4] , , , j − k > = i − 1 j-k>=i-1 j−k>=i−1
至于我们的既约分数的形式,我们直接使用gcd求出最小公约数即可
下面是具体的代码部分:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n;ll dp[1000][1000];
ll gcd(ll a,ll b) {
if(b==0) return a;
else return gcd(b,a%b);
}
int main() {
n=read();
dp[1][1]=1,dp[1][2]=1;dp[1][3]=1;dp[1][4]=1;
for(int i=2;i<=n;i++) {
for(int j=i;j<=4*i;j++) {
if(j-1>=i-1) dp[i][j]+=dp[i-1][j-1];
if(j-2>=i-1) dp[i][j]+=dp[i-1][j-2];
if(j-3>=i-1) dp[i][j]+=dp[i-1][j-3];
if(j-4>=i-1) dp[i][j]+=dp[i-1][j-4];
}
}
ll ans=0;ll ans2=0;
for(int i=n;i<=4*n;i++) {
ans+=dp[n][i];
if(i>=3*n) {
ans2+=dp[n][i];
}
}
if(ans==0) cout<<"1/1"<<endl;
else {
ll _gcd=gcd(ans,ans2);
cout<<ans2/_gcd<<"/"<<ans/_gcd<<endl;
}
return 0;
}