T1:三色地图
本题难度中等,用 dfs
一边遍历每个点,一边枚举每个点的颜色。
直接枚举每个点的颜色是 \(O(3^n)\) 会超时。所以在搜索时,要判断当前颜色是否和相邻点同色,如果同色要剪枝。原图不一定连通,所以要对每个连通块做染色搜索,将每个连通块的染色方案数相乘即为答案
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int n;
vector<vector<int>> to;
vector<int> used, col;
vector<int> vs;
void dfs(int v) {
if (used[v]) return;
used[v] = 1;
vs.push_back(v);
for (int u : to[v]) dfs(u);
}
ll now;
void dfs2(int i) {
if (i == vs.size()) { now++; return; }
int v = vs[i];
rep(c, 3) {
col[v] = c;
bool ok = true;
for (int u : to[v]) {
if (col[u] == c) ok = false;
}
if (!ok) continue;
dfs2(i + 1);
}
col[v] = -1;
}
int main() {
int m;
cin >> n >> m;
to = vector<vector<int>>(n);
rep(i, m) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
to[b].push_back(a);
}
ll ans = 1;
used = vector<int>(n);
col = vector<int>(n, -1);
rep(i, n) {
if (used[i]) continue;
ans *= 3;
vs = vector<int>();
dfs(i);
int s = vs.size();
col[vs[0]] = 0;
now = 0;
dfs2(1);
ans *= now;
}
cout << ans << '\n';
return 0;
}
T2: 最大值和最小值
本题难度较大,题目条件“最大数等于 \(x\),最小数等于 \(y\)” 可以看作:子段内所有数满足 \(y \leqslant a \leqslant x\) 且子段内含有至少一个 \(y\) 和至少一个 \(x\)。
我们考虑用 dp[i][1/2/3]
记录 "以 \(a_i\) 结尾的满足要求的子段个数",按照是否含有 \(x\) 或 \(y\) 分类讨论
最后要注意 \(x\) 和 \(y\) 有可能相同
- 若 \(x \neq y\),答案是 \(\sum dp[i][3]\)
- 若 \(x = y\),答案是 \(\sum dp[i][1]\)