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\),它的方案数就是:
其中 \(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\) 个位置。转移比较好懂:
- 单独放一组:\(f_{i,j,k} \leftarrow f_{i-1,j-1,k-1}\)。
- 和已有的一组连起来:\(f_{i,j,k}\leftarrow f_{i-1,j,k-a_i}\times j \times 2\)。
- 把已有的两组连起来:\(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 连通性


#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。

浙公网安备 33010602011771号