- 月赛题解
【202607】月赛语法组题解
- @ 2026-8-7 17:36:24
A
#include <iostream>
using namespace std;
int main()
{
int z1, z2, k1, k2;
cin >> z1 >> z2 >> k1 >> k2;
int cnt = 0;
cnt += (z1 == 1 && k1 == 3) || (z1 == 2 && k1 == 1) || (z1 == 3 && k1 == 2);
cnt += (z1 == 1 && k2 == 3) || (z1 == 2 && k2 == 1) || (z1 == 3 && k2 == 2);
cnt += (z2 == 1 && k1 == 3) || (z2 == 2 && k1 == 1) || (z2 == 3 && k1 == 2);
cnt += (z2 == 1 && k2 == 3) || (z2 == 2 && k2 == 1) || (z2 == 3 && k2 == 2);
cout << cnt * 25 << "%\n";
return 0;
}
B
#include <iostream>
using namespace std;
typedef long long ll;
int main() {
ll n, k;
cin >> n >> k;
if (n == 1) { // 只有1台机器,无需时间
cout << 0 << '\n';
return 0;
}
ll cnt = 1; // 已更新的机器数量
ll ans = 0; // 总耗时
// 阶段1:快速翻倍(数量<k,电缆够用)
while (cnt < k && cnt * 2 < n) {
cnt *= 2;
ans++;
}
// 阶段2:剩余机器匀速传输(每小时最多加k台)
ll rem = n - cnt;
// 向上取整:(rem + k -1) / k
ans += (rem + k - 1) / k;
cout << ans << '\n';
return 0;
}
C
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
long long l, r;
cin >> l >> r;
// 右边界:最大的奇数k,满足k² ≤ r
long long R = sqrt(r);
R = (R % 2 == 0) ? R - 1 : R;
// 左边界:最小的奇数k,满足k² ≥ l
long long L = sqrt(l - 1) + 1;
L = (L % 2 == 0) ? L + 1 : L;
// 计算个数,无结果则为0
cout << (L > R ? 0 : (R - L) / 2 + 1);
return 0;
}
D
小Z必胜,即他必须有一个手势,能赢过对方的两个手势。
使用数组存储胜负关系,并计数小Z的必胜手势种类数,记为 ,则这个必胜花样搭配其他任何一种手势都可以赢,左右手还可以互换,即总数为 。
注意这 种必胜手势两两选择被重复计数,因此要减去
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
int n, m, b[N][N], f, s;
char a[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
{
cin >> a[i][j];
if (a[i][j] == 'S')
b[i][j] = 1;
if (a[i][j] == 'F')
b[j][i] = 1;
}
while (m--)
{
cin >> f >> s;
int c = 0;
for (int i = 1; i <= n; i++)
c += (b[i][f] > 0 && b[i][s] > 0);
cout << c * (2 * n - c) << '\n';
}
}
E
因为初始 都是正数,所以可以发现,最后的答案一定是一段连续区间和。合并次数为 ,对应的是一段 的区间。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<ll> a(n + 1);
vector<ll> pre(n + 1, 0);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
pre[i] = pre[i - 1] + a[i];
}
int window = m + 1;
ll max_sum = 0;
for (int i = window; i <= n; i++)
{
ll cur = pre[i] - pre[i - window];
max_sum = max(max_sum, cur);
}
cout << max_sum << '\n';
return 0;
}
F
三个纯 1 数相加不会产生任何进位,最终的和一定是「高位连续的 1 + 中间连续的 2 + 低位连续的 3」的固定结构。
先计算最后结果的长度 ,可使用如下三重循环验证:
for (int i = 0; i <= len; i++)
for (int j = 0; i + j <= len; j++)
for (int k = 0; i + j + k <= len; k++)
cnt++;
可以发现在 时,。
然后继续枚举 各自的长度,存入结构体进行排序:
- 先按照总长度排序
- 长度相同时,按照 的数量排序
- 以上相同时,按照 的数量排序
最后定位出所要求的第 大的结果
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
struct Node
{
int i, j, k; // 分别对应1、2、3的个数
};
bool cmp(const Node &a, const Node &b)
{
int len_a = a.i + a.j + a.k;
int len_b = b.i + b.j + b.k;
// 1. 先按总长度从小到大
if (len_a != len_b)
return len_a < len_b;
// 2. 长度相同,1的个数越多越小
if (a.i != b.i)
return a.i > b.i;
// 3. 1的个数相同,2的个数越多越小
return a.j > b.j;
}
int main()
{
ios::sync_with_stdio(false);
cout.tie(nullptr);
int n;
cin >> n;
vector<Node> v;
// 枚举总长度,最多枚举到200足够覆盖n=5e5
for (int len = 1; len <= 200; len++)
{
// 枚举1的个数i
for (int i = 0; i <= len; i++)
{
// 枚举2的个数j
for (int j = 0; j <= len - i; j++)
{
int k = len - i - j;
// 3的个数至少为1
if (k >= 1)
v.push_back({i, j, k});
}
}
// 已经收集够n个以上就可以提前停,不用枚举更长的了
if (v.size() >= n)
break;
}
// 按数字从小到大排序
sort(v.begin(), v.end(), cmp);
// 取第n个(下标n-1)
Node ans = v[n - 1];
// 拼接输出
string res;
res.append(ans.i, '1');
res.append(ans.j, '2');
res.append(ans.k, '3');
cout << res << '\n';
return 0;
}
0 条评论
目前还没有评论...