这道题没啥规律,看了别人的题解发现可以组合枚举或者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;
}