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]\)