代码源挑战赛 Round 3
#13. [R3A]出现次数统计
#include <bits/stdc++.h>
using i64 = int64_t;
using vi = std::vector<i64>;
using std::cin, std::cout;
const int N = 5e5;
int main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
i64 n, x, res = 0;
cin >> n >> x;
for(i64 i = 1, y; i <= n; i ++) {
cin >> y;
res += (x == y);
}
cout << res;
return 0;
}
#14. [R3B]k次幂求和
#include <bits/stdc++.h>
using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;
#define int i64
const int mod = 998244353;
int power(int x, int y) {
int ans = 1;
while (y) {
if (y & 1) ans = ans * x % mod;
x = x * x % mod, y /= 2;
}
return ans;
}
i32 main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
int n, k;
cin >> n >> k;
int ans = 0;
for (int i = 0, x; i < n; i++) {
cin >> x;
ans = (ans + power(x, k)) % mod;
}
cout << ans << "\n";
return 0;
}
#15. [R3C]公因数求和
有一个很经典的式子,对于任何一个值\(x\),若被隐式分解后为
\[x = P_1^{c_1} \times P_2^{c_2} \dots P_m^{c_m}
\]
则\(x\)的所有因数和为
\[\Pi_{i=1} ^{m} (\sum_{j=0}^{c_i}P_i^j)
\]
#include <bits/stdc++.h>
using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;
#define int i64
const int mod = 998244353;
i32 main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
int x, y;
cin >> x >> y;
int d = std::gcd(x, y);
int res = 1;
for(int i = 2; i * i <= d; i ++) {
if(d % i != 0) continue;
int k = 0;
while(d % i == 0) k ++, d /= i;
int ans = 0, x = 1;
for(int j = 0; j <= k; j ++) {
ans += x;
x *= i;
}
res *= ans;
}
if(d != 1) res *= (d + 1);
cout << res;
return 0;
}
#16. [R3D]拼三角形
把所有的边排序,对于\(a < b < c\),则一定要满足\(len[a] + len[b] > len[c]\)。
假设固定了\(a\),则对于\(b\)和\(c\)来说,可以用双指针来求解。
#include <bits/stdc++.h>
using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;
#define int i64
const int mod = 998244353;
i32 main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vi len(n);
for(auto &i : len) cin >> i;
std::ranges::sort(len);
int res = 0;
for(int a = 0; a < n; a ++) {
for(int b = a + 1, c = b + 1; b < n and c < n; b ++) {
while(c + 1 < n and len[c + 1] < len[a] + len[b]) c ++;
if(len[a] + len[b] > len[c]) res += c - b;
}
}
cout << res << "\n";
return 0;
}
#17. [R3E]知识点学习
一个比较有意思的树形dp。
枚举\(f[x][i]\)表示以\(x\)为根的子树选择\(i\)个点的最优解。
可以枚举子节点\(y\),以及子节点的选择\(j\)个,则有\(f[x][i] = f[x][i - j] + f[y][j]\)这样的转移。
这里要注意的一个点就是如果\(y\)被选择了\(x\)一定要被选择,所以\(j < i\)。但是有一种特殊的情况就是当\(x=0\)时,就可以\(j=i\)。因为0号点不计入点数中。
#include <bits/stdc++.h>
using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;
#define int i64
const int mod = 998244353;
i32 main() {
std::ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
vi val(n + 1);
for (int i = 1; i <= n; i++) cin >> val[i];
std::vector<vi> e(n + 1);
for (int i = 1, fa; i <= n; i++) {
cin >> fa;
e[fa].push_back(i);
}
vi size(n + 1, 1);
size[0] = 0;
std::vector f(n + 1, vi(n + 1, 0));
auto dp = [&](auto &&self, int x) -> void {
f[x][1] = val[x];
for (auto y: e[x]) {
self(self, y);
for (int s = size[x] + size[y]; s >= 1; s--) {
for (int b = std::max(s - size[x], 0LL); b <= size[y] and ((b < s) or (x == 0 and b <= s)); b++) {
int a = s - b;
f[x][s] = std::max(f[x][s], f[x][a] + f[y][b]);
}
}
size[x] += size[y];
}
return;
};
dp(dp, 0);
cout << f[0][m] << "\n";
return 0;
}

浙公网安备 33010602011771号