小A买彩票 dp或枚举

本文探讨了小A购买彩票的策略,分析了彩票中奖概率以确定至少不亏本的概率。介绍了两种方法:一是使用动态规划(dp)计算不亏本的方案数,二是通过枚举1,2,3,4的组合并剔除质因子来计算。两种方法的时间复杂度分别是O(n^2)和O(n^3),并提供了相应的代码实现。" 81332752,7884357,Hyperledger Fabric:bootstrap.sh脚本详解,"['Hyperledger Fabric', '区块链', '脚本', 'Docker']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://ac.nowcoder.com/acm/contest/549/C
来源:牛客网
 

题目描述

小A最近开始沉迷买彩票,并且希望能够通过买彩票发家致富。已知购买一张彩票需要3元,而彩票中奖的金额分别为1,2,3,4元,并且比较独特的是这个彩票中奖的各种金额都是等可能的。现在小A连续购买了n张彩票,他希望你能够告诉他至少能够不亏本的概率是多少。

输入描述:

一行一个整数N,为小A购买的彩票数量

输出描述:

输出一个最简分数a/b,表示小A不亏本的概率。若概率为1,则输出1/1,概率为0,则输出0/1。

输入

2

输出

3/8

备注:

0≤n≤30

题解

牛客网给出的题解:

考虑买n张彩票的总的方案数是4^n,然后统计不亏本的方案数,记录f[i][j]是买到第i张彩票总获利为j的总方案数。f[i][j]=∑f[i−1][j−k],k=1,2,3,4最后统计一下不亏本的方案数即可。由于数据规模很小,考虑分别组合枚举有多少个1,2,3,4也可以通过。

复杂度:O(n^2)

       我当时没想到怎么dp,我组合枚举1,2,3,4的个数做的,复杂度O(n^3).   设1,2,3,4的个数分别为a,b,c,d,那么不亏的情况下应该满足 2a+b<d并且a+b+c+d==0, 满足上述条件下不亏的方案数应该是 a个1,b个2,c个3,d个4的全排列的个数。全排列的个数应该等于 n!/(a!*b!*c!*d!). 枚举a,b,c就可以算出所有不亏的方案数。 总的方案数应该等于4^n,等于2^(2n),直接通过位运算就可以算出来 long long sum=1LL<<2*n.然后算一下gcd约分就可以了。注意预处理阶乘的时候30的阶乘爆long long,那么可以用

long double 存储阶乘。显然不亏的情况数小于总方案数sum,所以最后再把long double 转成long long 计算gcd。

       或者用剔除质因子的方法算,把n!/(a!*b!*c!*d!) 分解质因子。这样就不会爆long long。每个大于2的正整数都可以化成质数相乘的式子。

 下边给出枚举1,2,3,4个数的代码和枚举1,2,3,4个数剔除质因子和dp代码:

枚举1,2,3,4个数,long double存储的代码:

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
typedef long long ll;
int n;
long double ans;
long double f[maxn];  //阶乘
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
int main(){
    cin>>n;
    f[0]=1;
    for(int i=1;i<=n;i++) f[i]=i*f[i-1];
    for(int a=0;a<=n;a++){
        for(int b=0;b<=n;b++){
            for(int c=0;c<=n;c++){
                int k=n-a-b-c;
                if(k<0) continue;
                if(2*a+b<=k){
                    ans+=f[n]/f[a]/f[b]/f[c]/f[k];
                }
            }
        }
    }
    ll ans1=(long long)(ans);
    ll y=1LL<<2*n;
    ll x=gcd(ans1,y);
    printf("%lld/%lld\n",ans1/x,y/x);
    return 0;
}

 枚举1,2,3,4个数,剔除质因子:

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
typedef long long ll;
int n;
ll ans;
int p[30]; 
int prime[10]={2,3,5,7,11,13,17,19,23,29};
int cnt=10; //质数个数
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
//算x的阶乘有多少因子y
int get(int x,int y){
    int s=0;
    while(x){
        s+=x/y;
        x/=y;
    }
    return s;
}
ll ksm(ll x,ll y){
    ll ans=1;
    while(y){
        if(y&1) ans*=x;
        y>>=1;
        x*=x;
    }
    return ans;
}
int main(){
    cin>>n;
    for(int a=0;a<=n;a++){
        for(int b=0;b<=n;b++){
            for(int c=0;c<=n;c++){
                int k=n-a-b-c;
                if(k<0) continue;
                if(2*a+b<=k){
                    for(int i=0;i<cnt;i++) p[prime[i]]=0;
                    for(int i=0;i<cnt;i++){
                        p[prime[i]]=get(n,prime[i])-get(a,prime[i])-get(b,prime[i])-get(c,prime[i])-get(k,prime[i]);
                    }
                    ll x=1;
                    for(int i=0;i<cnt;i++){
                        if(p[prime[i]]){
                            x*=ksm(prime[i],p[prime[i]]);
                        }
                    }
                    ans+=x;
                }
            }
        }
    }
    ll y=1LL<<2*n;
    ll z=gcd(ans,y);
    printf("%lld/%lld\n",ans/z,y/z);
    return 0;
}

dp代码:

#include<algorithm>
#include <iostream>
#include<cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=5e6+5;
ll dp[35][125];
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
int main(){
    int n;
    cin>>n;
    dp[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=i;j<=4*i;j++){
            for(int k=1;k<=4;k++){
                if(j-k>=0) dp[i][j]+=dp[i-1][j-k];
            }
        }
    }
    ll x=0;
    for(int i=3*n;i<=4*n;i++){
        x+=dp[n][i];
    }
    ll y=1LL<<2*n;
    ll z=gcd(x,y);
    printf("%lld/%lld\n",x/z,y/z);
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值