2025年10月模拟赛整合

2025年10月模拟赛整合

2025CSP-S模拟赛58

T1 T2 T3 T4
5 WA 100 AC 20 WA 75 TLE

总分:200;排名:6/25。

不知道为什么又在无意义罚坐。真的是把最显然的那一档打完之后就啥也不会做了,啥也想不出来。

除了 T2 是签到题,别的都是暴力。T4 应该是 45pts,数据水多了 30,T1 是骗分。

T1 铁轨

T2 参加

签到题

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
int n, a[N];
int f[N], g[N];

bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	n = read();
	for (int i = 1; i <= n; i++) {
		a[i] = read();
	}
	for (int i = 2; i <= n; i++) {
		f[i] = f[i - 1] + max(0ll, a[i - 1] - a[i] + 1);
	}
	for (int i = n - 1; i >= 1; i--) {
		g[i] = g[i + 1] + max(0ll, a[i + 1] - a[i] + 1);
	}
	int ans = INF;
	for (int i = 1; i <= n; i++) {
		ans = min(ans, max(f[i], g[i]));
	}
	printf("%lld\n", ans);
	Usd();
	return 0;
}

T3 决斗

T4 回文串问题

2025CSP-S模拟赛59

T1 T2 T3 T4
80 WA 20 WA 0 TLE 20 WA

总分:120;排名:6/25。

这场比较刺激。T1 其实 A 了,但是忘记特判 \(n=1\) 挂了 20pts。最开始想了 2h 容斥,都崩了,所谓柳暗花明又一村啊,突然想出来了,码出来了,然后发现样例 2 没过。此时大概过了 2.8 h,还一分没有,去写了写 T2,10 pts。T3 拆贡献不会。发现 T1 少乘了个东西,加上直接把样例全过了。最后 0.4h 写了写 T4,写了点性质。

T1 一个赢家

这个是自己想的。

考虑算出只有一个最大值的方案数,最后除以总方案数即可。

考虑枚举最大值。不难发现,令最大值为 \(i\),则 \(i=[2n+1,4n-1]\)。然后手玩或者推一下就发现这个最大值的构成(由哪两个数加起来)一共有 \(\lceil\frac{4n-i}{2} \rceil\) 种。我们把这个值记作 \(x\)。在这 \(x\) 种构成种,我们随便钦定一个为唯一最大值。不妨设 \(i\) 的另一种构成是 \(i=a+b\),且 \(a>b\)。那么 \(a\) 肯定要和一个 \(c\) 去结合(\(c<b\))。然后你就发现,对于每个 \(a\)\(c\),都有 \(i-2n-1\) 种取值。自己简单推一下就能发现。然后上述这 \(x\) 组数都处理完之后,应该还剩下 \(2n-2x\) 个数,这些数随便组合即可,都不会大于 \(i\)

总的来讲,对于每个 \(i\),它的方案数就是:

\[x\times (i-2n-1)^{x-1}\times f_{2n-2x} \]

其中 \(f_n\) 就是 \(n\) 个数随便组合的方案数。这个是好求的。

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int MOD = 1e9 + 7;
const int N = 1e7 + 10;
int n;
il int fpow(int a, int x) {
	a %= MOD;
	int ans = 1;
	while (x) {
		if (x & 1) ans = ans * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return ans;
}
int fact[N], ny[N];
il int C(int n, int m) {
	return n < m ? 0 : fact[n] * ny[m] % MOD * ny[n - m] % MOD;
}
int all[N];
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	n = read();
	if (n == 1) return printf("1\n"), 0;
	fact[0] = 1;
	for (int i = 1; i <= 2 * n; i++) fact[i] = fact[i - 1] * i % MOD;
	ny[2 * n] = fpow(fact[2 * n], MOD - 2);
	for (int i = 2 * n - 1; i >= 0; i--) ny[i] = ny[i + 1] * (i + 1) % MOD;
	all[1] = 1;
	for (int i = 3; i <= 2 * n; i += 2) {
		all[i] = all[i - 2] * i % MOD;
	}
	int sum = 0;
	for (int i = 4 * n - 1; i >= 2 * n + 1; i--) {
		int x = (4 * n - i + 1) / 2;
		int s = fpow(i - 2 * n - 1, x - 1);
		sum = (sum + x * s % MOD * all[2 * n - 2 * x - 1]) % MOD;
	}
	int ans = sum * fpow(all[2 * n - 1], MOD - 2) % MOD;
	printf("%lld\n", ans);
	
	Usd();
	return 0;
}

T2 磁铁

是一个连续段 dp。

首先把磁铁从小到大排序,方便处理。\(f_{i,j,k}\) 表示放了 \(i\) 个磁铁,分了 \(j\) 组,占用了 \(k\) 个位置。转移比较好懂:

  1. 单独放一组:\(f_{i,j,k} \leftarrow f_{i-1,j-1,k-1}\)
  2. 和已有的一组连起来:\(f_{i,j,k}\leftarrow f_{i-1,j,k-a_i}\times j \times 2\)
  3. 把已有的两组连起来:\(f_{i,j,k} \leftarrow f_{i-1,j+1,k-2a_i+1} \times \frac{j\times(j+1)}{2}\)

答案即为:\(\sum f_{n,1,k}\times \tbinom{m-k+n}{n}\)

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int MOD = 1e9 + 7;
const int N = 55 + 10, M = 1e4 + 10;
int n, m, a[N];
il void add(int &a, int b) {
	a = a + b >= MOD ? a + b - MOD : a + b;
}
il int fpow(int a, int x) {
	a %= MOD;
	int ans = 1;
	while (x) {
		if (x & 1) ans = ans * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return ans;
}
int fact[M], ny[M];
il int C(int n, int m) {
	return n < m ? 0 : fact[n] * ny[m] % MOD * ny[n - m] % MOD;
}
int f[N][N][M];
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	n = read(), m = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	fact[0] = 1;
	for (int i = 1; i <= m; i++) fact[i] = fact[i - 1] * i % MOD;
	ny[m] = fpow(fact[m], MOD - 2);
	for (int i = m - 1; i >= 0; i--) ny[i] = ny[i + 1] * (i + 1) % MOD;
	sort(a + 1, a + 1 + n);
	f[0][0][0] = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= i; j++) {
			for (int k = 1; k <= m; k++) {
				add(f[i][j][k], f[i - 1][j - 1][k - 1]);
				if (k >= a[i]) add(f[i][j][k], f[i - 1][j][k - a[i]] * j % MOD * 2 % MOD);
				if (k >= 2 * a[i] - 1) add(f[i][j][k], f[i - 1][j + 1][k - 2 * a[i] + 1] * j % MOD * (j + 1) % MOD);
			}
		}
	}
	int ans = 0;
	for (int k = n; k <= m; k++) {
		add(ans, f[n][1][k] * C(m - k + n, n) % MOD);
	}
	printf("%lld\n", ans);
	
	Usd();
	return 0;
}

T3 树上染色

T4 摆放花盆

2025CSP-S模拟赛60

T1 T2 T3 T4
100 AC 0 WA 5 WA 0 WA

总分:105;排名:21/25。

T1 简单,T2 写了 3h,后面没做。

T1 数列变换

简单题不说了。

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 5e5 + 10;
int n, m, qq, a[N], b[N];
int s[N], num[N];
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	n = read(), m = read(), qq = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	for (int i = 1; i <= m; i++) b[i] = read();
	for (int i = 1; i <= m; i++) {
		s[i] = s[i - 1] + (i % 2 == 0 ? 1 : -1) * b[i];
	}
	for (int i = 0; i <= m - n; i++) {
		num[i] = (i % 2 == 0 ? -1 : 1) * (s[i + n] - s[i]);
	}
	sort(num, num + m - n + 1);
	int sum = 0;
	for (int i = 1; i <= n; i++) {
		sum += (i % 2 == 0 ? -1 : 1) * a[i];
	}
	int ans = INF;
	int id = lower_bound(num, num + m - n + 1, sum) - num;
	if (id > 0) ans = min(ans, abs(sum - num[id - 1]));
	if (id <= m - n + 1) ans = min(ans, abs(sum - num[id]));
	printf("%lld\n", ans);
	while (qq--) {
		int l = read(), r = read(), v = read();
		if (l > r) swap(l, r);
		if ((r - l + 1) % 2 == 1) {
			sum += (r % 2 == 0 ? -1 : 1) * v;
			ans = INF;
			id = lower_bound(num, num + m - n + 1, sum) - num;
			if (id > 0) ans = min(ans, abs(sum - num[id - 1]));
			if (id <= m - n + 1) ans = min(ans, abs(sum - num[id]));
		}
		printf("%lld\n", ans);
	}
	Usd();
	return 0;
}

T2 排列计数

这个题做法挺多的。首先原问题转化为:求一个数组的合法排列数,使得相同元素不相邻。

考试时一直在想组合数,最后当然没做出来。也拿容斥和 dp 做过,都没有做出来。

赛后看了眼 dp 状态就会做了。真的很巧妙。

\(f_{i,j}\) 表示放了前 \(i\) 种数,其中有 \(j\) 组相邻的相同的数(\(j\) 个不合法空隙),的方案数。

然后就做完了。

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int MOD = 1e9 + 7;
const int N = 605;
int n, a[N];
il int fpow(int a, int x) {
	a %= MOD;
	int ans = 1;
	while (x) {
		if (x & 1) ans = ans * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return ans;
}
int fact[N], ny[N];
il int C(int n, int m) {
	return n < m ? 0 : fact[n] * ny[m] % MOD * ny[n - m] % MOD;
}
int ll[N], t[N], s[N];
int f[N][N];
il void add(int &x, int y) {
	x = x + y >= MOD ? x + y - MOD : x + y;
}
il int solve() {
	n = read();
	for (int i = 1; i <= n; i++) t[i] = 0;
	for (int i = 1; i <= n; i++) {
		a[i] = read();
		int x = a[i];
		for (int j = 2; j * j <= a[i]; j++) {
			while (x % (j * j) == 0) x /= (j * j);
		}
		a[i] = x;
		ll[i] = a[i];
	}
	sort(ll + 1, ll + 1 + n);
	int lll = unique(ll + 1, ll + 1 + n) - ll - 1;
	for (int i = 1; i <= n; i++) {
		a[i] = lower_bound(ll + 1, ll + 1 + lll, a[i]) - ll;
		t[a[i]]++;
	}
	for (int i = 1; i <= lll; i++) {
		s[i] = s[i - 1] + t[i];
	}
	for (int i = 0; i <= lll; i++) 
		for (int j = 0; j <= n; j++) f[i][j] = 0;
	f[0][0] = 1;
	for (int i = 1; i <= lll; i++) {
		for (int j = 0; j <= n - lll; j++) {
			if (!f[i - 1][j]) continue;
			for (int k = 0; k < t[i]; k++) {
				for (int l = 0; l <= min(j, k + 1); l++) {
					add(f[i][j - l + t[i] - 1 - k], f[i - 1][j] * C(t[i] - 1, k) % MOD * C(j, l) % MOD * C(s[i - 1] + 1 - j, k + 1 - l) % MOD);
				}
			}
		} 
	}
	int ans = f[lll][0];
	for (int i = 1; i <= lll; i++) {
		ans = ans * fact[t[i]] % MOD;
	}
	printf("%lld\n", ans);
	
	return 0;
}
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	fact[0] = 1;
	for (int i = 1; i <= 600; i++) fact[i] = fact[i - 1] * i % MOD;
	ny[600] = fpow(fact[600], MOD - 2);
	for (int i = 599; i >= 0; i--) ny[i] = ny[i + 1] * (i + 1) % MOD;
	int qq = read();
	while (qq--) {
		solve();
	}
	Usd();
	return 0;
}

T3 子串调整

T4 最小生成树

CSP-S模拟赛加赛

T1 T2 T3 T4
100 AC 60 RE 15 TLE 37 WA

总分:212;排名:4/5。

T1 A 了,T2 部分分,T3 挂了 20 分,T4 干了 1.5h,思路基本正确,码力太差细节太多,最后输出 0。

T1 Divisors

不难,不说了。

#include <bits/stdc++.h>
#define il inline

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int N = 200 + 10;
int n, m, a[N];
int p[20000000], tot;
int ans[N];
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	n = read(), m = read();
	for (int i = 1; i <= m; i++) {
		a[i] = read();
	}
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j * j <= a[i] && j <= n; j++) {
			if (a[i] % j == 0) {
				p[++tot] = j;
				if (a[i] / j <= n) p[++tot] = a[i] / j;
			}
		}
	}
	sort(p + 1, p + 1 + tot);
	tot = unique(p + 1, p + 1 + tot) - p - 1;
	for (int i = 1; i <= tot; i++) {
		int cnt = 0;
		for (int j = 1; j <= m; j++) {
			cnt += (a[j] % p[i] == 0);
		}
		ans[cnt]++;
	}
	ans[0] = n;
	for (int k = 1; k <= m; k++) ans[0] -= ans[k];
	for (int k = 0; k <= m; k++) {
		printf("%d\n", ans[k]);
	}
	Usd();
	return 0;
}

T2 Market

\(t\) 排序依次处理得思路不难想到,跑朴素得 01 背包即可。

正解算一个有点类似与背包的 dp。\(f_i\) 表示价值为 \(i\) 的最小花费。这就很巧妙地解决了 \(M_i\)\(c_i\) 过大得问题。令 \(g_i=\min_{j=i}^V f_j\),即 \(f\) 的后缀最小值。查询就是在 \(g\) 上 lower_bound 即可。其实不难。

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 300 + 10, M = 1e5 + 10, maxn = 90000 + 10;
int n, m;
struct node {
	int c, v, t;
	il bool operator < (const node & cmp) const {
		return t < cmp.t;
	}
} a[N];
struct nodeq {
	int t, m, id;
	il bool operator < (const nodeq & cmp) const {
		return t < cmp.t;
	}
} qq[M];
int f[maxn], mn[maxn];
int ans[M];
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	n = read(), m = read();
	for (int i = 1; i <= n; i++) {
		int c = read(), v = read(), t = read();
		a[i] = {c, v, t};
	}
	for (int i = 1; i <= m; i++) {
		int t = read(), mm = read();
		qq[i] = {t, mm, i};
	}
	sort(a + 1, a + 1 + n);
	sort(qq + 1, qq + 1 + m);
	a[n + 1].t = INF;
	int sum = 0;
	for (int i = 1; i <= n; i++) sum += a[i].v;
	for (int i = 1; i <= sum; i++) f[i] = INF;
	for (int i = 0; i < maxn; i++) mn[i] = INF;
	for (int i = 1, j = 1; j <= m; i++) {
		for (; j <= m && qq[j].t < a[i].t; j++) {
			ans[qq[j].id] = upper_bound(mn, mn + 1 + sum, qq[j].m) - mn - 1;
		}
		if (j > m) break;
		for (int k = sum; k >= a[i].v; k--) {
			f[k] = min(f[k], f[k - a[i].v] + a[i].c);
		}
		for (int k = sum; k >= 0; k--) {
			mn[k] = min(f[k], mn[k + 1]);
		}
	}
	for (int i = 1; i <= m; i++) {
		printf("%lld\n", max(0ll, ans[i]));
	}
	Usd();
	return 0;
}

T3 连通性

o_251020115717_22222.png (743×675) (cnblogs.com)

o_251020115717_11111.png (739×487) (cnblogs.com)

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
const int MOD = 1e9 + 7;
const int N = 100 + 10;
int n, m;
int fact[N], ny[N];
il int fpow(int a, int x) {
	a %= MOD;
	int ans = 1;
	while (x) {
		if (x & 1) ans = ans * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return ans;
}
il int C(int n, int m) {
	return n < m ? 0 : fact[n] * ny[m] % MOD * ny[n - m] % MOD;
}
int f[N][N], g[N]; 
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	fact[0] = 1;
	n = 100;
	for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % MOD;
	ny[n] = fpow(fact[n], MOD - 2);
	for (int i = n - 1; i >= 0; i--) ny[i] = ny[i + 1] * (i + 1) % MOD;
	for (int i = 0; i <= n; i++) f[i][0] = fpow(2, C(i, 2));
	for (int i = 1; i <= n; i++) {
		g[i] = f[i][0];
		for (int j = 1; j < i; j++) {
			g[i] = (g[i] - g[j] * C(i - 1, j - 1) % MOD * f[i - j][0] % MOD) % MOD;
		}
		g[i] = (g[i] + MOD) % MOD;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= i; j++) {
			for (int k = 1; k <= j; k++) {
				f[i][j] = (f[i][j] + f[i - k][j - k] * C(j - 1, k - 1) % MOD) % MOD;
				for (int l = 1; l <= i - j; l++) {
					f[i][j] = (f[i][j] + f[i - k - l][j - k] * C(j - 1, k - 1) % MOD * C(i - j, l) % MOD * f[k][0] % MOD * g[l] % MOD * fpow(fpow(2, l) - 1, k) % MOD) % MOD;
				}
			}
		}
	}
	int qq = read();
	while (qq--) {
		n = read(), m = read();
		printf("%lld\n", (f[n][m] + MOD) % MOD);
	}
	Usd();
	return 0;
}

T4 树

其实考场上就想到了,但是没码出来。

对于每条链,我们给他一个颜色 \(v_i\)。考虑做一个树剖套线段树,线段树每一个节点维护当前这个点的颜色是什么,即 \(tree[p].c \in \pm v_{i\in[1,m]}\)。正负分别代表他是向上或向下(具体的不重要,只要区分开就行)。对于每种颜色进行并查集(即视作 \(m\) 个点),然后对于每种颜色维护 \(sta_x \in \{1,-1\}\),表示 \(x\)\(fa_x\) 的颜色是否相同。然后对于没条链进行树链修改,在线段树 pushup 的同时进行颜色的合并。那么一个点实际的颜色就是 \(tree[p].c \times sta[|c|]\)。然后在此过程中如有 \(fa_{|x|}=fa_{|y|} \land x=-y\) 的情况即为无解。在线段树更新信息的过程中维护即可。

统计答案比较简单。假设并查集最后有 \(a\) 个连通块,\(b\) 个点到最后没有颜色,那么 \(ans=2^{a+b}\)

代码细节比较多,但是没码出来。

#include <bits/stdc++.h>
#define il inline

using namespace std;

const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
bool Beg;
#define abs(x) (x > 0 ? x : -x)
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 3e5 + 10;
int n, m;
vector<int> G[N];
il void Stop() {
	printf("0\n");
	exit(0);
}
int id[N], tot, top[N], siz[N], son[N], dep[N], fa[N];
il void dfs1(int x, int father) {
	fa[x] = father;
	dep[x] = dep[fa[x]] + 1;
	siz[x] = 1;
	for (int y : G[x]) {
		if (y == fa[x]) continue;
		dfs1(y, x);
		siz[x] += siz[y];
		if (siz[y] > siz[son[x]]) son[x] = y;
	}
}
il void dfs2(int x, int t) {
	top[x] = t;
	id[x] = ++tot;
	if (!son[x]) return;
	dfs2(son[x], t);
	for (int y : G[x]) {
		if (y == fa[x] || y == son[x]) continue;
		dfs2(y, y);
	}
}
il int getlca(int x, int y) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		x = fa[top[x]];
	}
	if (dep[x] < dep[y]) swap(x, y);
	return y;
}
int f[N], sta[N];
il int getfa(int x) {
	if (x == f[x]) return x;
	int r = getfa(f[x]);
	sta[x] *= sta[f[x]];
	return f[x] = r;
}
struct node {
	int l, r, c, lazy;
} tree[N << 2];
#define lc p << 1
#define rc p << 1 | 1
il void build(int p, int l, int r) {
	tree[p].l = l, tree[p].r = r;
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(lc, l, mid), build(rc, mid + 1, r);
}
il void pushdown(int p) {
	if (!tree[p].lazy) return;
	tree[lc].lazy = tree[p].lazy;
	tree[rc].lazy = tree[p].lazy;
	tree[lc].c = tree[p].c;
	tree[rc].c = tree[p].c;
	tree[p].lazy = 0;
	return;
}
il int query(int p, int x) {
	if (tree[p].l == tree[p].r) return tree[p].c;
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (x <= mid) return query(lc, x);
	else return query(rc, x);
}
il void pushup(int p) {
	if (!tree[lc].c || !tree[rc].c) {
		tree[p].c = tree[lc].c + tree[rc].c;
	} else if (tree[lc].c == tree[rc].c) {
		tree[p].c = tree[lc].c;
	} else {
		tree[p].c = INF;
	}
}
il void upd(int p, int l, int r, int c) {
	if (!tree[p].c) {
		tree[p].c = c;
		tree[p].lazy = c;
	} else if (tree[p].c != INF) {
		int x = getfa(abs(c)), y = getfa(abs(tree[p].c));
		int cx = c * sta[abs(c)], cy = tree[p].c * sta[abs(tree[p].c)];
		if (x != y) {
			f[y] = x;
			if (1ll * cx * cy < 0) {
				sta[y] = -1;
			} else {
				sta[y] = 1;
			}
		} else if (x == y && 1ll * cx * cy < 0) {
			Stop();
		}
		tree[p].c = cx;
		tree[p].lazy = cx;
	} else {
		pushdown(p);
		int mid = (l + r) >> 1;
		upd(lc, l, mid, c);
		upd(rc, mid + 1, r, c);
		pushup(p);
	}
}
il void update(int p, int l, int r, int c) {
	if (l > r) return;
	if (tree[p].l == l && tree[p].r == r) {
		upd(p, l, r, c);
		return;
	}
	pushdown(p);
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (r <= mid) update(lc, l, r, c);
	else if (l > mid) update(rc, l, r, c);
	else update(lc, l, mid, c), update(rc, mid + 1, r, c);
	pushup(p);
}
il void update_path(int x, int y, int v) {
	int lca = getlca(x, y);
	sta[v] = 1;
	while (top[x] != top[y]) {
		if (dep[top[x]] > dep[top[y]]) {
			update(1, id[top[x]] + (top[x] == lca), id[x], v);
			x = fa[top[x]];
		} else {
			update(1, id[top[y]] + (top[y] == lca), id[y], -v);
			y = fa[top[y]];
		}
	}
	if (dep[x] > dep[y]) {
		update(1, id[y] + 1, id[x], v);
	} else {
		update(1, id[x] + 1, id[y], -v);
	}
}
int vis[N];
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
	n = read(), m = read();
	for (int i = 1; i < n; i++) {
		int x = read(), y = read();
		G[x].push_back(y);
		G[y].push_back(x);
	}
	dfs1(1, 0);
	dfs2(1, 1);
	build(1, 1, n);
	for (int i = 1; i <= m; i++) f[i] = i;
	for (int i = 1; i <= m; i++) {
		int x = read(), y = read();
		update_path(x, y, i);
	}
	int cnt = 0;
	for (int i = 1; i <= m; i++) {
		int x = getfa(i);
		if (!vis[x]) {
			cnt++;
			vis[x] = 1;
		}
	}
	long long ans = 1;
	for (int i = 1; i <= cnt; i++) {
		ans = ans * 2 % MOD;
	}
	for (int i = 2; i <= n; i++) {
		if (query(1, id[i]) == 0) {
			ans = ans * 2 % MOD;
		}
	}
	printf("%lld\n", ans);
	Usd();
	return 0;
}

HZ CSP-S模拟赛36

懒得写总结了,把分一登。

T1 T2 T3 T4
0 TLE 50 WA 0 WA 0 WA

总分:85;排名:20/29。

HZ CSP-S模拟赛37(CSP-S模拟赛65)

T1 T2 T3 T4
60 WA 100 AC 0 RE 26 WA

总分:186;排名:5/12。

HZ CSP-S模拟赛38(CSP-S模拟赛66)

T1 T2 T3 T4
20 TLE 100 AC 70 RE 10 TLE

总分:200;排名:2/8,11/33。

HZ CSP-S模拟赛39(CSP-S模拟赛67)

T1 T2 T3 T4
100 AC 20 RE 100 AC 100 AC

总分:320;排名:5/22,14/32。

HZ CSP-S模拟赛40(CSP-S模拟赛68)

T1 T2 T3 T4
80 RE 100 AC 15 RE -

总分:195;排名:1/35。

HZ CSP-S模拟赛41(CSP-S模拟赛69)

T1 T2 T3 T4
60 WA 30 WA 60 WA 10 TLE

总分:160;排名:6/12,17/33。

HZ CSP-S模拟赛42(CSP-S模拟赛67)

T1 T2 T3 T4
60 TLE 25 TLE 10 RE 10 WA

总分:105;排名:7/14,12/30。

HZ CSP-S模拟赛37(CSP-S模拟赛65)

T1 T2 T3 T4
100 AC 100 AC 10 WA 35 TLE

总分:245;排名:2/14。

posted @ 2025-10-31 08:38  Zctf1088  阅读(17)  评论(0)    收藏  举报