HBCPC 2023 湖北省赛
M. Different Billing
题目大意
有三种队伍参加比赛,A类免费,B类缴费1000元,C类缴费2500元,已知x个队伍参赛,收费y元,求任意满足的一组ABC
解题思路
暴力枚举c倒推ba判断合法性即可
代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int x, y, a, b = 0, c = -1;
std::cin >> x >> y;
for (int i = 0; i <= 1e9 / 2500; i++) {
c++;
b = (y - 2500 * c) / 1000;
a = x - b - c;
if (1000 * b + 2500 * c == y && a >= 0 && b >= 0 && c >= 0) {
std::cout << a << " " << b << " " << c << "\n";
return 0;
}
}
std::cout << -1 << "\n";
}
C. Darkness I
题目大意
有一个n*m的黑白矩阵,如果一个白格和两个黑格相邻,则它会被染黑,问矩阵初始至少要有多少个黑格才能让整个矩阵被染黑
解题思路
选一侧长和宽间隔着染黑即可
代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n, m;
std::cin >> n >> m;
std::cout << (m + n + 1) / 2 << "\n";
}
K. Dice Game
题目大意
n+1个人玩1个m面的骰子,如果最小值有多个则会重投骰子,问当固定第一个人投出1~m的点数时输的概率
解题思路
当投出和第一个人相同点数的时候始终都会重投,因此有效的点数为m-1,获胜的点数为m-i,最终的概率为\((\frac{m-i}{m-1})^n\)
代码实现
#include <bits/stdc++.h>
using i64 = long long;
const int MOD = 998244353;
i64 ksm(i64 a, i64 n, i64 mod) {
i64 res = 1;
a = (a % mod + mod) % mod;
while (n) {
if (n & 1) {
res = (a * res) % mod;
}
a = (a * a) % mod;
n >>= 1;
}
return res;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n, m;
std::cin >> n >> m;
for (int i = 1; i <= m; i++) {
std::cout << ksm(m - i, n, MOD) * ksm(ksm(m - 1, n, MOD), MOD - 2, MOD) % MOD << " \n"[i == m];
}
}
H. Binary Craziness
题目大意
给定一张图,定义函数 \(f(u, v) = (deg_u \bigoplus deg_v)(deg_u | deg_v)(deg_u \& deg_v)\),\(deg_u\)表示\(u\)的度,求\(\sum_{i=1}^{n} \sum_{j=i}^{n} f(i,j)\%998244353\)
解题思路
显然图中的节点会有大量重复的度,因此统计度的大小和数量,暴力枚举即可,注意数据范围可能爆longlong和重边
代码实现
#include <bits/stdc++.h>
using i64 = long long;
using i128 = __int128;
const int MOD = 998244353;
i64 ksm(i64 a, i64 n, i64 mod) {
i64 res = 1;
a = (a % mod + mod) % mod;
while (n) {
if (n & 1) {
res = (a * res) % mod;
}
a = (a * a) % mod;
n >>= 1;
}
return res;
}
std::ostream &operator<<(std::ostream &out, i128 val) {
if (val == 0) {
return out << "0";
}
if (val < 0) {
out << '-', val = -val;
}
std::string s;
while (val > 0) {
s += '0' + val % 10;
val /= 10;
}
std::reverse(s.begin(), s.end());
return out << s;
}
std::istream &operator>>(std::istream &in, i128 &val) {
std::string s;
in >> s;
val = 0;
bool neg = (s[0] == '-');
for (int i = neg; i < s.size(); i++) {
val = val * 10 + (s[i] - '0');
}
if (neg) {
val = -val;
}
return in;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
i128 n, m;
std::cin >> n >> m;
std::vector<i128> in(n + 1);
std::set<std::array<i128, 2>> edge;
for (int i = 0; i < m; i++) {
i128 u, v;
std::cin >> u >> v;
if (u > v) {
std::swap(u, v);
}
edge.insert({u, v});
}
for (auto [u, v] : edge) {
in[u]++;
in[v]++;
}
std::map<i128, i128> mp;
for (auto x : in) {
if (x) {
mp[x]++;
}
}
i128 ans = 0;
for (auto [x1, y1] : mp) {
for (auto [x2, y2] : mp) {
ans += y2 * y1 % MOD * ((x1 ^ x2) * (x1 | x2) % MOD * (x1 & x2) % MOD);
ans %= MOD;
}
}
std::cout << ans * ksm(2, MOD - 2, MOD) % MOD << "\n";
}
J. Expansion
题目大意
初始你在一个资源数组的0位置并且有0的资源,每秒你可以选择向后移动一位或者停留在原地,然后得到前缀和的资源,如果走到了末尾则会一直停留,要求无限时间下资源都不能小于0,问在这种情况下第几秒走到最末尾的位置,如果不可能则输出-1
解题思路
首先处理每一步的前缀和,要保证首尾两个数字必须是非负,同时要记录走到这一步时之前的最大值,途中遇到负数和的时候在这里补充资源是最优的,遍历整个前缀数组即可,特判无法补充的情况
代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n;
std::cin >> n;
std::vector<i64> a(n), pre(n + 1);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
pre[i + 1] = pre[i] + a[i];
}
if (pre[1] < 0 || pre[n] < 0) {
std::cout << -1 << "\n";
return 0;
}
i64 ans = 0, now = 0, max = 0;
for (int i = 1; i <= n; i++) {
now += pre[i];
max = std::max(max, pre[i]);
ans++;
if (now < 0) {
if (max <= 0) {
ans = -1;
break;
}
ans += (-now + max - 1) / max;
now += (-now + max - 1) / max * max;
}
}
std::cout << ans << "\n";
}
F. Inverse Manacher
题目大意
构造一个ab字符串,要求满足Manacher算法下的中心回文长度数组,保证有解
解题思路
分割符的中心回文长度是1则发生了字符交替,直接模拟即可
代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int n;
std::cin >> n;
std::vector<int> a(2 * n + 2);
for (int i = 0; i <= 2 * n + 1; i++) {
std::cin >> a[i];
}
std::string ans = "a";
for (int i = 3, f = 0; i < 2 * n; i += 2) {
if (a[i] == 1) {
ans += "ab"[f ^= 1];
} else {
ans += "ab"[f];
}
}
std::cout << ans << "\n";
}
I. Step
题目大意
给定一个数组a,找到最小的t使得t(t+1)是2*lcm(a)的倍数
解题思路
对2lcm质因数分解,质数的数量一定不会太多(最小的16个质数相乘都超过1e18了),dfs暴力枚举每一个质因数的幂是属于t(设为a)还是t+1(设为b),而a与b,t与t+1都是互质的,因此可以联系到求解方程ax+by=gcd(a,b)=1的最小ax,exgcd枚举途中取最小即可
代码实现
#include <bits/stdc++.h>
using i64 = long long;
using i128 = __int128;
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
namespace Factorizer {
std::vector<int> primes, least;
void sieve(int n) {
std::vector<int> nums;
least.assign(n + 1, 0);
for (int i = 2; i <= n; i++) {
if (least[i] == 0) {
least[i] = i;
nums.push_back(i);
}
for (auto p : nums) {
if (i * p > n) {
break;
}
least[i * p] = p;
if (p == least[i]) {
break;
}
}
}
primes = nums;
}
bool miller_rabin(i64 n) {
if (n <= 1 || (n != 2 && n % 2 == 0)) {
return false;
}
for (auto a : {3, 5, 7, 11, 13, 17, 19, 23, 29}) {
if (n % a == 0) {
return n == a;
}
}
if (n < 31 * 31) {
return true;
}
i64 d = n - 1;
while (d % 2 == 0) {
d /= 2;
}
for (i64 a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
if (n == a) {
return true;
}
i64 t = d, y = 1 % n;
for (i64 _t = t; _t != 0; _t >>= 1) {
if (_t & 1) {
y = (i128)y * a % n;
}
a = (i128)a * a % n;
}
while (t != n - 1 && y != 1 && y != n - 1) {
y = (i128)y * y % n;
t <<= 1;
}
if (y != n - 1 && t % 2 == 0) {
return false;
}
}
return true;
}
i64 pollard_rho(i64 n) {
if (n == 1 || miller_rabin(n)) {
return n;
}
i64 now = 0;
do {
i64 t = std::gcd(++now, n), r = t, g = 1;
if (t != 1 && t != n) {
return t;
}
do {
t = ((i128)t * t % n + now) % n;
r = ((i128)r * r % n + now) % n;
r = ((i128)r * r % n + now) % n;
} while ((g = std::gcd(abs(t - r), n)) == 1);
if (g != n) {
return g;
}
} while (now < n / now);
return 0;
}
std::vector<i64> factor(i64 n) {
if (n == 1) {
return {};
}
std::vector<i64> g, d;
d.push_back(n);
while (!d.empty()) {
auto v = d.back();
d.pop_back();
auto rho = pollard_rho(v);
if (rho == v) {
g.push_back(rho);
} else {
d.push_back(rho);
d.push_back(v / rho);
}
}
std::sort(g.begin(), g.end());
return g;
}
} // namespace Factorizer
void exgcd(i64 a, i64 b, i64 &x, i64 &y) {
if (b == 0) {
x = 1, y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= a / b * x;
}
int main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
i64 n, lcm = 1;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
lcm = std::lcm(lcm, a[i] * 2);
}
std::vector<i64> fac = Factorizer::factor(lcm), f;
std::unordered_map<i64, i64> ump;
for (auto x : fac) {
if (ump.count(x)) {
ump[x] *= x;
} else {
ump[x] = x;
}
}
for (auto [x, y] : ump) {
f.push_back(y);
}
i64 siz = f.size(), ans = 4e18;
auto dfs = [&](auto &&self, int pos, i64 a) {
if (pos == siz) {
i64 x = 0, y = 0, b = lcm / a;
exgcd(a, b, x, y);
x = ((-x) % b + b) % b;
if (x == 0) {
x = b;
}
ans = std::min(ans, a * x);
return;
}
self(self, pos + 1, a);
self(self, pos + 1, a * f[pos]);
};
dfs(dfs, 0, 1);
std::cout << ans << "\n";
}

浙公网安备 33010602011771号