题意
在某个游戏中有一个骰子游戏。在游戏中,你需要投掷 5 个标准六面骰子(骰子为一个正方体,6 个面上分别有1、2、3、4、5、6中的一个数字,骰子的质量均匀),投出的点数根据组合会获得一个“获胜等级”。获胜等级从高到低如下:
- 五个同点数 - 五个骰子显示相同的点数
- 四个同点数 - 四个骰子显示相同的点数
- 葫芦 - 一对和一个三个同点数(如1、1、3、3、3)
- 六高顺子 - 投出的点数为 2、3、4、5、6
- 五高顺子 - 投出的点数为 1、2、3、4、5
- 三个同点数 - 三个骰子显示相同的点数(如1、1、1、2、3)
- 两对 - 投出的点数中有两对是相同的(如 1、1、2、2、3)
- 一对 - 投出的点数有一对是相同的(如 1、1、2、3、4)
- 无 - 除去以上的其他情况
要选择任意骰子重投一次,要在重投后获得更好的等级的概率最大,要选择多少骰子?如果概率相同,选择更少的骰子
输入样例
3
1 1 2 2 3
1 1 2 3 4
1 1 1 2 3
输出样例
3 4 9
3 13 18
2 4 9
题解
不可能是每种等级有固定方案的
一共才5个骰子,n^2的级别也才25加5次询问
那关键就是,要怎么算概率
首先确定成功条件,写check函数来将当前情况分级,每次改动之后就查看是否到达更高的级别
每个位置的更改只有5种可能,一共5个位置,可以用DFS暴搜所有的可能更改,因为修改还有数量限制,所以DFS退出条件应该修改过的骰子数量,如果改完后级别更高,就记录
那么概率怎么算? 每次多修改一个骰子的分母会乘上6
每次修改的分子会是修改该数量骰子后,DFS成功达到高级别的次数,也就是只要记录下成功的次数,就可以得到该方案的概率
此时要用到状态压缩,因为修改的数量相同,修改位置不同属于不同的方案,首先要遍历不同数量,再状态压缩该数量下遍历不同的方案,记录修改的位置(数组存储),用这些位置DFS对原数组进行修改(改到新数组里),每次修改后判别是否到达下一级别,是就 cnt++
#include <bits/stdc++.h>
using namespace std;
const int N = 7;
int a[N], b[N], n = 5;
struct ANS {
int x, y, cnt;
};
ANS ans;
int cnt, p;
vector<int> v;
int check(int a[])
{
map<int, int> mp;
for(int i = 1; i <= n; i ++)
{
mp[a[i]] ++;
}
if((int)mp.size() == 1) return 1;
if((int)mp.size() == 2)
{
for(auto y: mp)
{
if(y.second == 4) return 2;
if(y.second == 3) return 3;
}
}
if((int)mp.size() == 5)
{
if(!mp.count(1)) return 4;
else if(!mp.count(6)) return 5;
}
if((int)mp.size() == 3)
{
for(auto y: mp)
{
if(y.second == 3) return 6;
if(y.second == 2) return 7;
}
}
if((int)mp.size() == 4)
return 8;
return 9;
}
void dfs(int now)
{
//要修改的数达到要求了
if(now == (int)v.size())
{
if(check(b) < p) ++ cnt;
return;
}
for(int i = 1; i <= 6; ++ i)
{
b[v[now]] = i;
//遍历所有的修改方法
dfs(now + 1);
}
}
void solve()
{
for(int i = 1; i <= n; ++ i)
{
cin >> a[i];
}
//重置答案
ans = {0, 0, 0};
p = check(a);
if(p == 1)
{
cout << 0 << ' ' << 0 << ' ' << 1 << endl;
return;
}
//分母
int q = 1;
for(int k = 1; k <= n; ++ k)
{
//分母先乘上6
q *= 6;
//ans通分
ans.x *= 6, ans.y *= 6;
for(int i = 0; i < 1 << n; ++ i)
{
if(__builtin_popcount(i) != k)
continue;
v.clear();
//存放修改这些位置,达到更高级别的分子
cnt = 0;
for(int j = 1; j <= 5; ++ j)
{
//重置赋值b为a
b[j] = a[j];
}
for(int j = 0; j < 5; ++ j)
{
//记录要修改的位置
if(i >> j & 1)
{
v.push_back(j + 1);
}
}
dfs(0);
//如果分母为0,直接赋值
if(ans.y == 0) ans = {cnt, q, k};
else
{
if(cnt > ans.x)
{
ans = {cnt, q, k};
}
}
//而且从小到大遍历k,同样大小的分子不会更新为大的k的情况
}
}
int g = __gcd(ans.x, ans.y);
cout << ans.cnt << ' ' << ans.x / g << ' ' << ans.y / g << endl;
}
int main()
{
int t;
cin >> t;
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
while(t --)
{
solve();
}
return 0;
}
难度还可以,只要在于实现