题解 | 牛客周赛 Round 58
感觉有点思维的一场。(QWQ)
A. 会赢吗?
思路
判断 是否大于
即可,由于是与
位浮点数比较大小,所以需要通过判断两者差值的绝对值是否不超过
来判断两者是否相等。
代码实现
// Problem: 会赢吗?
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/89510/A
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
double w, h;
cin >> w >> h;
if (h > w && fabs(h - w) > 1e-7)
cout << "YES";
else
cout << "NO\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--) {
solve();
}
}
B. 能做到的吧
思路
只要存在一个数位的数字,后面的数位存在比该数字大的数字,那么交换之后就可以把 变大。
代码实现
// Problem: 能做到的吧
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/89510/B
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
string s;
cin >> s;
for (int i = 0; i < s.size(); i++) {
for (int j = i + 1; j < s.size(); j++) {
if (s[i] < s[j]) {
cout << "YES\n";
return;
}
}
}
cout << "NO\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
C. 会赢的!
会赢的,牢师!
思路
原先想着 抛出所有的博弈状态,但是发现还存在平手的问题。
转换思路,可以发现从 走到
的步数是确定的
步。
如果不是选择最优策略,而是轮到那个人,就往 的方向走一步,那么这种情况下赢的人是根据
的奇偶性确定,奇数先手赢,偶数后手赢。
下面分类讨论(令 ):
1, 为奇数
如果后手不动手脚的话是先手赢,后手此时最优的情况只可能是平手,而要实现平手,把棋子走越界即可,最少走越界的方法显然是向 方向,对应走
步,而先手对应的最优决策则是向
方向走。
如果后手能走 步使得棋子越界,那么在后手走
步时,先手无法多走一步到达终点,也就是说
不是终点。
因此,这种情况下,如果 则先手赢,否则平局。
2, 为偶数
和奇数思路同理,不过是交换先后手,如果 ,终点为
,则先手无法在到达终点之前让棋子越界,否则先手则可以有多走几步的空间,使得棋子越界。
因此,这种情况下,如果 则先手输,否则平局。
3, 或者
此时一定无法移动到终点,绝对平局。
代码实现
// Problem: 会赢的!
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/89510/C
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// Problem: 能做到的吧
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/89510/B
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
int x, y;
void solve()
{
cin >> x >> y;
if (x > y)
swap(x, y);
if (x < 0 || y < 0) {
cout << "PING\n";
} else if (x == y) {
cout << "NO\n";
} else {
if ((x + y) % 2) {
cout << (y == x + 1 ? "YES" : "PING") << '\n';
} else {
cout << (x == y ? "NO" : "PING") << '\n';
}
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
D. 好好好数
思路
好数,实则就是
进制下每个数位上不超过
的数字。
如果 在
进制下,所有的数位上的最大数字为
,那么最少就需要
个
数来凑出
。
特殊情况则是 的时候,此时所有数都可以表示为
好数,
可以表示为
。
代码实现
// Problem: 好好好数
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/89510/D
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n, k;
cin >> n >> k;
if (k == 1) {
cout << 1 << '\n';
return;
}
int ni = n;
int ans = 0;
while (ni) {
ans = max(ans, ni % k);
// 找出 k 进制下数位的最大数字
ni /= k;
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
E. 好好好数组
思路
手玩一下,可以发现,不同数字最多为 个。
不同数字为一个的情况只有一种,即 个
。
不同数字为两个的情况有 种,即起初为一段
,然后到
的位置之后都是
。例如像
这样子。
不同数字为三个的情况只有一种,即开头为 ,中间一段都为
,末尾为
,即
这样子。
而题目中是不少于 个,因此如果
不大于
个,则总情况数增加
个对应的情况数。
代码实现
// Problem: 好好好数组
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/89510/E
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e7 + 5;
int n, m;
void solve()
{
cin >> n >> m;
int ans = 0;
if (m <= 1)
ans++;
if (m <= 2)
ans += n - 1;
if (m <= 3)
ans++;
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
F. 随机化游戏时间?
思路
令 为当前幸运数的范围,初始为
。
如果区间 存在
个数字小于等于幸运数,那么幸运数一定不小于区间的第
大,且小于区间的第
大。
令区间的第 大为 v,第
大为
,那么幸运数的范围变化为
]。(注意当
如果为
或者
时,对应的左边界或者右边界不需要更新)
查询静态区间第 大,可以使用可持久化线段树处理。
最后得到幸运数的范围 ,猜对数字的概率即为
,如果范围长度为
则直接输出幸运数。
因为最后答案是对 取模,涉及到分数求逆元,可以用快速幂解决。
代码实现
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5;
#define ls(x) (tr[x].l)
#define rs(x) (tr[x].r)
#define sum(x) tr[x].sum
int n, m;
int a[N];
int tot;
int root[N];
struct {
int l, r, sum;
} tr[25 * N];
void pushup(int u)
{
sum(u) = sum(ls(u)) + sum(rs(u));
}
void modify(int now, int last, int l, int r, int p)
{
if (l == r) {
sum(now) = sum(last) + 1;
} else {
ls(now) = ls(last), rs(now) = rs(last);
int mid = (l + r - 1) / 2;
if (p <= mid) {
ls(now) = ++tot;
modify(ls(now), ls(last), l, mid, p);
} else {
rs(now) = ++tot;
modify(rs(now), rs(last), mid + 1, r, p);
}
pushup(now);
}
}
const int L = -1e9, R = 1e9;
int kth(int now, int last, int l, int r, int k)
{
if (l == r)
return l;
int mid = (l + r - 1) / 2;
int cur = sum(ls(now)) - sum(ls(last));
if (cur >= k)
return kth(ls(now), ls(last), l, mid, k);
else
return kth(rs(now), rs(last), mid + 1, r, k - cur);
}
int query(int now, int last, int l, int r, int li, int ri)
{
if (li <= l && r <= ri)
return sum(now) - sum(last);
int res = 0;
int mid = (l + r - 1) / 2;
if (li <= mid)
res += query(ls(now), ls(last), l, mid, li, ri);
if (ri > mid)
res += query(rs(now), rs(last), mid + 1, r, li, ri);
return res;
}
int kth(int now, int last, int k)
{
int l = L, r = R;
while (l < r) {
int mid = (l + r - 1) / 2;
int val = query(now, last, L, R, L, mid);
if (val < k)
l = mid + 1;
else
r = mid;
}
return r;
}
int mod = 1e9 + 7;
int qmi(long long a, int b)
{
int res = 1;
while (b) {
if (b & 1)
res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
void solve()
{
tot = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
root[i] = ++tot;
modify(root[i], root[i - 1], L, R, a[i]);
}
int L = 1, R = n;
while (m--) {
int l, r, k;
cin >> l >> r >> k;
if (k == r - l + 1)
L = max(L, kth(root[r], root[l - 1], k));
else if (k == 0)
R = min(R, kth(root[r], root[l - 1], k + 1) - 1);
else {
L = max(L, kth(root[r], root[l - 1], k));
R = min(R, kth(root[r], root[l - 1], k + 1) - 1);
}
}
int len = R - L + 1;
if (len != 1)
cout << qmi(R - L + 1, mod - 2) << '\n';
else
cout << 1 << ' ' << R << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
solve();
}
}