[语言月赛 202409] 转盘 的题解
记住只在没有思路时使用题解,不要从它复制粘贴代码。请尊重题目和题解的作者。
在解题之前提交题解的代码会导致封禁。
在解题之前提交题解的代码会导致封禁。
作者:
概述
本题要求找出获奖概率不低于 的最小奖级,即满足
的最小整数
(
),无解时输出
。核心解法是把条件等价变形为
,直接对
向上取整得到答案。
分析
核心观察
中 等奖的概率为
,随
单调递增;条件
等价于
,因此最小的合格奖级就是
。
思路
奖盘共被分成 份,条件
等价于:
故答案 (
时取
);若
,说明概率最大的
等奖也不达标,输出
。
向上取整必须用精确整数运算: 最大约
,double 计算
的误差可达
,而该值到最近整数的距离最小只有
,浮点版本会在边界处取错。因此把
解析为精确分数
:
若不用闭式,也可从小到大枚举奖级 检查
,第一个满足的
与上式结果一致。
具体示例
样例 :
,
,
,
,向上取整得
,输出
。样例
:
,
,
,向上取整得
,输出
。
算法步骤
- 读入
n与浮点数m。 - 将
m解析为精确分数:整数部分与小数部分合并为M(),
d为小数位数。 - 计算
sum为。
- 计算
k为(用整数除法实现,即
),并取
k与的较大值。
- 若
k不超过n,输出k;否则输出。
复杂度分析
时间:
空间:
实现注意事项
最大约
,超出 64 位整数范围,C++ 中需使用 128 位整数(__int128),Python 的大整数可直接处理。
- 向上取整不能先浮点计算再取整:
的 double 误差(约
)远大于其与整数的最小距离(
),会在边界处出错。
时任意奖级都满足条件,答案应为
,注意对计算结果取
。
- 无解条件为
,即概率最大的
等奖仍不达标。
源代码
#include <bits/stdc++.h>
using namespace std;
int main() {
long long n;
string m;
cin >> n >> m;
long long M = 0;
int d = 0;
size_t dot = m.find('.');
if (dot == string::npos) {
M = stoll(m);
} else {
string ip = m.substr(0, dot);
string fp = m.substr(dot + 1);
d = (int)fp.size();
long long ipv = ip.empty() ? 0 : stoll(ip);
long long fpv = fp.empty() ? 0 : stoll(fp);
M = ipv;
for (int i = 0; i < d; i++) M *= 10;
M += fpv;
}
long long sum = n * (n + 1) / 2;
long long den = 1;
for (int i = 0; i < d + 2; i++) den *= 10;
__int128 k128 = ((__int128)sum * M + den - 1) / den;
long long k = (long long)k128;
if (k < 1) k = 1;
if (k > n) cout << -1 << '\n';
else cout << k << '\n';
return 0;
}
n, m = input().split()
n = int(n)
if '.' in m:
ip, fp = m.split('.', 1)
d = len(fp)
M = (int(ip) if ip else 0) * 10**d + (int(fp) if fp else 0)
else:
d = 0
M = int(m)
total = n * (n + 1) // 2
den = 10 ** (d + 2)
k = (total * M + den - 1) // den
k = max(k, 1)
print(k if k <= n else -1)
评论