2025 CSP-S 模拟赛 13

2025 CSP-S 模拟赛 13

\(\text{Link}\)

得分

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 相似

咕咕咕。

posted @ 2025-07-10 09:55  UKE_Automation  阅读(45)  评论(0)    收藏  举报