2025CSP-S模拟赛13 比赛总结
2025CSP-S模拟赛13
怎么感觉这几天都在和数据斗智斗勇。。
T1 马
考试时写了一个神秘贪心,和出题人玩心里博弈。根据我们精湛的骗分技术,也是骗到了 90pts 的高分。
直接来看正解。
有什么可说的。这么简单的 dp 想不出来不就是**。我是**!我是**!我是**!
说一个最简单的思路吧。考虑 \(f_{t,i,j,k}\) 表示考虑到第 \(t\) 匹马,当前三种活动分别满足了 \(i,j,k\) 个人。转移不就是:
#include <bits/stdc++.h>
using namespace std;
int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x;
}
#define max(x, y) (x > y ? x : y)
#define min(x, y) (x < y ? x : y)
const int INF = 0x3f3f3f3f;
const int N = 150 + 5, M = 300 + 5, K = 100 + 5;
const int maxn = 100;
int n, m, a[5];
int f[2][M][M][M];
int main() {
n = read(), m = read(), a[1] = read(), a[2] = read(), a[3] = read();
int a1 = a[1], a2 = a[2], a3 = a[3];
memset(f, 0x3f, sizeof(f));
int ans = 0;
int z = 0;
f[z][0][0][0] = 1;
for (int id = 1; id <= n; id++) {
z ^= 1;
for (int i = 0; i <= a1; i++) {
for (int j = 0; j <= a2; j++) {
for (int k = 0; k <= a3; k++) {
if (f[z ^ 1][i][j][k] <= 100) f[z][i][j][k] = 1;
else f[z][i][j][k] = INF;
}
}
}
for (int i = 0; i <= a1; i++) {
for (int j = 0; j <= a2; j++) {
for (int k = 0; k <= a3; k++) {
if (i) f[z][i][j][k] = min(f[z][i][j][k], f[z][i - 1][j][k] + 50);
if (j) f[z][i][j][k] = min(f[z][i][j][k], f[z][i][j - 1][k] + 20);
if (k) f[z][i][j][k] = min(f[z][i][j][k], f[z][i][j][k - 1] * 2);
if (f[z][i][j][k] <= 100) {
ans = max(ans, i + j + k);
}
}
}
}
}
printf("%d\n", ans);
return 0;
}
T2 可爱捏
懒得写了,直接复制 bobo 的题解。。
初步思路
由于最终的判定条件是两数乘积是否为立方数,所以可以先对所有数预处理——将其所有质因子的次数模 3,这样得到的数质因子指数只能是 1 或 2 方便处理(指数为 3 的倍数的可以忽略),并且可以很好地保持两个数乘积在立方数判定意义下的性质。
首先判掉一些好判的数方便后续处理。如果原数列中出现了立方数,则在集合 S 中他们最多只能出现一个,只需 ans 加 1 然后跳过处理这些数。
然后考虑对于每一个数分解因数后,把每个因子指数模 3 后相乘,处理出一个数 \(x\)。然后我们需要处理出一个数\(y\),使得 \(x \times y\) 为一个完全立方数。然后,把 \(x\) 和 \(y\) 映射到 map 中。我们称这样的 \(x\) 和 \(y\) 是对应的,则查询是一组对应的数中取出现次数较多的一个即可。
30pts
考虑数据范围,则在根号时间内将所有数质因数分解是可以接受的,在分解的过程中将数以上述思路处理,之后再遍历一遍所有的处理后的数,统计答案,时间复杂度\(O(n\sqrt{a_{i}}+n\log n)\) (用 \(a_{i}\) 代指值域)。
100pts
值域如果是 \(10^{10}\) 在以根号的时间复杂度分解质因数就不可接受了。考虑优化将每一个数 \(a_{i}\) 处理成其对应的 \(x\)(或对应 \(y\))的过程。考虑只将每一个 \(a_{i}\) 中小于 \(\sqrt[3]{a_{i}}\) 的因子分解出来处理,这样 \(a_{i}\) 就只剩下大于 \(\sqrt[3]{a_{i}}\) 的质因子了,易证他此时剩下的部分 \(m\) 最多只能被分解成两个质因子之积(因为此时小于 \(\sqrt[3]{a_i}\) 的因子已经被分解出去了,所以 \(m\) 的因子都大于 \(\sqrt[3]{a_i}\),若有多于两个的因子则 \(m\) 的值将会大于 \(a_i\) )。考虑分类讨论:
- \(m = 1\) 此时已经分解完成。
- \(m\) 为一个大于 \(\sqrt[3]{a_{i}}\) 的质数,则 \(y\) 为前面求出 \(y\) 的一部分乘上 \(m^2\) (注意如果 \(a_i\) 对应的 \(y\) 大于了 \(10^{10}\) 则可以直接选入 S)。
- \(m\) 为两个不同质数相乘 ,情况同2处理,因为质因数质数都为 1。
- \(m\)为两个相同质数相乘,则 \(y\) 为前面求出 \(y\) 的一部分乘上 \(\sqrt{m}\)。
之后处理相同,时间复杂度 \(O(n\sqrt[3]{a_{i}}+n\log n)\)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x;
}
const int N = 1e5 + 10;
int n, a[N];
unordered_map<int, int> mp, vis;
int b[N], c[N];
signed main() {
n = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
int x = a[i];
int num = 1, num1 = 1;
for (int j = 2; j * j * j <= a[i]; j++) {
if (x % j == 0) {
int cnt = 0;
while (x % j == 0) {
cnt++;
x /= j;
}
cnt %= 3;
if (cnt == 1) num *= j, num1 *= j * j;
if (cnt == 2) num *= j * j, num1 *= j;
}
}
if (x > 1) {
int xx = sqrt(x);
if (xx * xx == x) {
num *= xx * xx;
num1 *= xx;
} else {
num *= x;
num1 *= x * x;
}
}
mp[num]++;
b[i] = num, c[i] = num1;
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (vis[b[i]]) continue;
vis[b[i]] = vis[c[i]] = 1;
if (b[i] == 1) {
ans++;
continue;
}
ans += max(mp[b[i]], mp[c[i]]);
}
printf("%lld\n", ans);
return 0;
}
T3 诗
有什么可说的!\(n^2\) 过十万!!暴力哈希就可以直接 AC !!!
#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x;
}
const int P = 131;
const int N = 1e5 + 10;
int n, qq, op, lastans;
int s[N], t[N];
ull p[N], hsh[N];
inline ull gethsh(int l, int r) {
return hsh[r] - hsh[l - 1] * p[r - l + 1];
}
int main() {
op = read(), n = read(), qq = read();
for (int i = 1; i <= n; i++) {
s[i] = read();
}
p[0] = 1;
for (int i = 1; i < N; i++) p[i] = p[i - 1] * P;
for (int i = 1; i <= n; i++) {
hsh[i] = hsh[i - 1] * P + s[i];
}
while (qq--) {
int len = read();
ull h = 0;
for (int i = 1; i <= len; i++) {
t[i] = read() ^ lastans;
h = h * P + t[i];
}
int ans = 0;
for (int i = 1; i + len - 1 <= n; i++) {
ans += (h == gethsh(i, i + len - 1));
}
printf("%d\n", ans);
if (op) lastans = ans;
}
return 0;
}

浙公网安备 33010602011771号