CSP-S模拟赛加赛 比赛总结
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;
}

浙公网安备 33010602011771号