2025 CSP-S 模拟赛 13
2025 CSP-S 模拟赛 13
得分
| T1 | T2 | T3 | T4 | Sum | Rank |
|---|---|---|---|---|---|
| \(100\) | \(15\) | \(40\) | \(40\) | \(195\) | \(4/19\) |
题解
T1 马
考虑 dp,容易想到设 \(dp(i,a,b,c)\) 表示当前用到第 \(i\) 匹马,剩余要求数分别为 \(a,b,c\) 是否可行。先枚举出一匹马可能的所有操作,然后直接转移即可。这样复杂度是 \(O(nm^3)\) 的,无法通过。发现这个 dp 的值域是 \(0/1\),非常浪费,考虑将任意的一维放到值域中即可。复杂度 \(O(m^3)\) 或 \(O(nm^2)\)。
#include <bits/stdc++.h>
#define pii pair<int, int>
#define mk make_pair
#define fi first
#define se second
#define il inline
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
x = 0; char ch = getchar(); bool flg = 0;
for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
static short Stk[50], Top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do Stk[++Top] = x % 10, x /= 10; while(x);
while(Top) putchar(Stk[Top--] | 48);
typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;
int n, m;
int a, b, c;
vector <pair<pii, int>> V;
vector <int> e;
il void dfs(int x, int w) {
if(w + 20 > 100 && w * 2 > 100) {
int c1 = 0, c2 = 0, c3 = 0;
for(auto p : e) {
if(p == 1) c1++;
if(p == 2) c2++;
if(p == 3) c3++;
}
V.push_back(mk(mk(c1, c2), c3));
return ;
}
if(w + 20 <= 100) {
e.push_back(1);
dfs(x + 1, w + 20);
e.pop_back();
}
if(w + 50 <= 100) {
e.push_back(2);
dfs(x + 1, w + 50);
e.pop_back();
}
if(w * 2 <= 100) {
e.push_back(3);
dfs(x + 1, w * 2);
e.pop_back();
}
}
int dp[155][305][305];
bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
dfs(1, 1);
read(n), read(m);
read(b), read(a), read(c);
for(int i = 0; i <= n; i++) for(int j = 0; j <= a; j++) for(int k = 0; k <= b; k++) dp[i][j][k] = Inf;
dp[0][a][b] = c;
for(int i = 0; i < n; i++) {
for(int j = 0; j <= a; j++) {
for(int k = 0; k <= b; k++) {
if(dp[i][j][k] == Inf) continue;
for(auto p : V) {
int _a = p.fi.fi, _b = p.fi.se, _c = p.se;
int t1 = max(j - _a, 0), t2 = max(k - _b, 0), t3 = max(dp[i][j][k] - _c, 0);
chkmin(dp[i + 1][t1][t2], t3);
}
}
}
}
int ans = 0;
for(int j = 0; j <= a; j++) {
for(int k = 0; k <= b; k++) {
if(dp[n][j][k] == Inf) continue;
chkmax(ans, a - j + b - k + c - dp[n][j][k]);
}
}
write(ans);
Usd();
return 0;
}
T2 可爱捏
发现我们可以将每个数质因子的指数对 \(3\) 取模,这样的话得到的数字可以两两配对,每一组里面我们选取个数更多的那一边即可。这个步骤可以简单用 map 实现。
然后考虑我们如何拆质因子,暴力的想法自然是 \(O(\sqrt V)\) 拆质因子,不过这样的话总复杂度达到了 \(O(n\sqrt V)\),难以通过。直接的想法是利用 Pollard-Rho 做到 \(O(V^{\tfrac 14})\) 拆质因子,即可直接通过。不过对于本题来讲,我们有更加简单的方式。
考虑一个结论:一个数中 \(>\sqrt[3]{V}\) 的质因子最多两个,我们先将 \(\le \sqrt[3]{V}\) 的质因子拆出来,然后剩下的质因子最多两个。如果这两个质因子不相同,那么直接平方即可得到与之配对的数的对应部分;否则的话开平方根即可。这样可以做到 \(O(\sqrt[3]{V})\) 拆质因子,也可以通过。
#include <bits/stdc++.h>
#define il inline
#define int long long
#define ll __int128
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
x = 0; char ch = getchar(); bool flg = 0;
for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
static short Stk[50], Top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do Stk[++Top] = x % 10, x /= 10; while(x);
while(Top) putchar(Stk[Top--] | 48);
typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;
int n, mx, a[Maxn];
unordered_map <int, int> mp, num;
int tot, ans;
il void work(int v) {
ll res1 = 1, res2 = 1;
for(int i = 2; i * i * i <= v; i++) {
int cnt = 0;
while(v % i == 0) v /= i, cnt++;
cnt %= 3;
if(cnt == 1) res1 = res1 * i, res2 = res2 * i * i;
else if(cnt == 2) res1 = res1 * i * i, res2 = res2 * i;
}
int t = sqrt(v);
if(t * t == v) res1 = res1 * v, res2 = res2 * t;
else res1 = res1 * v, res2 = res2 * v * v;
if(res1 == 1) {tot++; return ;}
if(mp.find(res1) == mp.end() && mp.find(res2) == mp.end()) mp[res1] = res2;
num[res1] += 1;
}
bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
signed main() {
// freopen("data.txt", "r", stdin);
read(n);
for(int i = 1; i <= n; i++) {
read(a[i]);
}
for(int i = 1; i <= n; i++) {
work(a[i]);
}
if(tot) ans++;
for(auto p : mp) {
int a = p.first, b = p.second;
ans += max(num[a], num[b]);
}
write(ans);
Usd();
return 0;
}
考场上硬是没想到用 Pollard-Rho 分解,遗憾离场。
T3 诗
板子题都不会做了……
首先这是一个 SAM 的板子,不过这不在 CSP 范围内。
题目中给出了一个部分分是模式串串长 \(\le 50\),这启发我们进行阈值分治。考虑一个阈值 \(B\),当串长小于 \(B\) 时采取该子任务的方式,暴力枚举预处理出哈希值并存起来,查询的时候直接查询即可;而串长大于 \(B\) 的最多只有 \(\tfrac{\sum l}{B}\) 个,暴力枚举求解即可。
这样总复杂度为 \(O(Bn+\tfrac{n\sum l}B)\),取 \(B=\sqrt n\) 最优,复杂度 \(O(n\sqrt n)\)。
#include <bits/stdc++.h>
#define il inline
using namespace std;
typedef unsigned long long ull;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
const int p = 1200007;
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
x = 0; char ch = getchar(); bool flg = 0;
for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
static short Stk[50], Top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do Stk[++Top] = x % 10, x /= 10; while(x);
while(Top) putchar(Stk[Top--] | 48);
typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;
int opt;
int n, q, s[Maxn];
ull base[Maxn], hsh[Maxn];
#define B 100
unordered_map <ull, int> mp[B + 5];
bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
// freopen("sample_poem5.in", "r", stdin);
// freopen("my.out", "w", stdout);
read(opt), read(n), read(q);
int mx = 0;
for(int i = 1; i <= n; i++) read(s[i]);
base[0] = 1;
for(int i = 1; i <= n; i++) base[i] = base[i - 1] * p;
for(int i = 1; i <= n; i++) hsh[i] = hsh[i - 1] * p + s[i];
for(int len = 1; len <= B; len++) {
for(int i = 1; i + len - 1 <= n; i++) {
ull hs = hsh[i + len - 1] - hsh[i - 1] * base[len];
mp[len][hs]++;
}
}
int lst = 0;
while(q--) {
int k; read(k);
ull hs = 0;
for(int i = 1; i <= k; i++) {
int ch; read(ch);
if(opt == 1) ch ^= lst;
hs = hs * p + ch;
}
lst = 0;
if(k <= B) {
lst = mp[k][hs];
}
else {
for(int i = 1; i + k - 1 <= n; i++) {
ull h = hsh[i + k - 1] - hsh[i - 1] * base[k];
if(h == hs) lst++;
}
}
write(lst);
}
Usd();
return 0;
}
T4 相似
咕咕咕。

浙公网安备 33010602011771号