2022 暑假水题选做
20220627
P3914 染色计数
思路:考虑树形 dp。设 \(f_{u,i}\) 为考虑以 \(u\) 为根的子树且 \(u\) 染上 \(i\) 时的答案,则:
\[f_{u,i}=\prod_{v\in\operatorname{son}(u)}\sum_{j\ne i}f_{v,j} \]后面的 \(\sum\) 可以通过维护 \(\sum_{i=1}^m f_{u,i}\) 来优化掉。
算法:dp。
技巧:通过处理某些东西优化复杂度。
想到了的:都想到了。
没想到的:无。
代码
#include
#include
using namespace std;
const int N = 5000, P = 1e9 + 7;
struct Edge {
int to, nxt;
} e[N * 2 + 10];
int head[N + 10], tote;
void addEdge(int u, int v) {
e[++tote] = {v, head[u]};
head[u] = tote;
}
int n, m, f[N + 10][N + 10], sum[N + 10];
void dfs(int u, int _fa) {
for (int _ = head[u]; _; _ = e[_].nxt) {
int v = e[_].to;
if (v == _fa) continue;
dfs(v, u);
for (int i = 1; i <= m; i++)
f[u][i] = 1LL * f[u][i] * ((sum[v] - f[v][i]) % P) % P;
}
for (int i = 1; i <= m; i++)
(sum[u] += f[u][i]) %= P;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
while (x--) {
int y; scanf("%d", &y);
f[i][y] = 1;
}
}
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
addEdge(u, v), addEdge(v, u);
}
dfs(1, 0);
printf("%d\n", (sum[1] % P + P) % P);
return 0;
}
CF1677C Tokitsukaze and Two Colorful Tapes
思路:先拆置换,对于每个置换,填法一定是 \(\max,\min,\max,\min,\cdots\)。对于一个长度为 \(m\) 的置换,“山峰”有 \(\left\lfloor\frac m2\right\rfloor\) 个,“山谷”有 \(m-\left\lfloor\frac m2\right\rfloor\) 个,而每个山峰 \(x\) 对答案的贡献为 \(2x\),每个山谷 \(x\) 对答案的贡献为 \(-2x\)。那么当我们让最大的数做山峰时答案有最大值 \(2\sum\left\lfloor\frac m2\right\rfloor(n-\sum\left\lfloor\frac m2\right\rfloor)\)。
算法:贪心。
技巧:拆置换、分别考虑每个数对答案的贡献。
想到了的:拆置换、贪心。
没想到的:考虑贡献。
代码
#include
#include
using namespace std;
const int N = 1e5;
int n, a[N + 10], b[N + 10], pos[N + 10];
bool vis[N + 10];
void mian() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
for (int i = 1; i <= n; i++)
scanf("%d", b + i), pos[b[i]] = i;
int peak = 0;
for (int i = 1; i <= n; i++) {
int x = i, cnt = 0;
while (1) {
if (vis[x]) break;
vis[x] = 1;
cnt++;
x = pos[a[x]];
}
peak += cnt / 2;
}
printf("%lld\n", 2LL * peak * (n - peak));
}
int main() {
int T; scanf("%d", &T);
while (T--) {
for (int i = 1; i <= n; i++)
a[i] = b[i] = pos[i] = vis[i] = 0;
mian();
}
return 0;
}