牛客每日一题——小A买彩票

题目连接

在这里插入图片描述
这道题没啥规律,看了别人的题解发现可以组合枚举或者DP,或者记忆化搜索

先说一下组合枚举
总数据 4^n 最大 4 ^ 30 long double可以存下。
组合枚举总中奖 元,2元,3元,4元的个数,也就是三重for循环,复杂度O(n^3),设1,2,3,4的个数分别是 a,b,c,d,那么对于不亏的情况,应该满足 2a+b<=d ,并且 a+b+c+d=n,满足上述条件下不亏方案的总个数应该是 a个1,b个2,c个3,d个4的全排列个数,应该等于n!/(a!*b!*c!*d!),枚举a,b,c就可以算出所有不亏的方案数。

DP
n张彩票要想不亏本,最后的金额必须再3n到4n之间,定义dp[i][j]代表 i 张彩票中奖 j 元的方案数

组合枚举代码

#include <iostream>
#include <cstdio>
#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;
}

DP代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 5;
typedef long long ll;
int n;
ll dp[250][500],sum; //阶乘
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}
int main()
{
	cin >> n;
	dp[0][0]=1;
	for(int i=1;i<=n;++i)
	for(int j=i;j<=4*i;++j)
        dp[i][j]+=dp[i-1][j-1]+dp[i-1][j-2]+dp[i-1][j-3]+dp[i-1][j-4];

	for(int i=3*n;i<=4*n;++i)
		sum+=dp[n][i];

	ll sum = (long long)(sum);
	ll y = 1LL << 2 * n;
	ll x = gcd(sum, y);
	printf("%lld/%lld\n", sum / x, y / x);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值