// 检查某一种颜色是否已经形成五连 boolcheck(vector<vector<int>> &board, int color){ for (int i = 0; i < 5; i++) { if (board[i][0] == color && board[i][1] == color && board[i][2] == color && board[i][3] == color && board[i][4] == color) { returnfalse; } if (board[0][i] == color && board[1][i] == color && board[2][i] == color && board[3][i] == color && board[4][i] == color) { returnfalse; } }
if (board[0][0] == color && board[1][1] == color && board[2][2] == color && board[3][3] == color && board[4][4] == color) { returnfalse; }
if (board[0][4] == color && board[1][3] == color && board[2][2] == color && board[3][1] == color && board[4][0] == color) { returnfalse; }
returntrue; }
// pos:当前处理到第几个格子(0~24) // black:当前已经放了多少个黑棋 voidsolve(vector<vector<int>> &board, int pos, int black, int &ans){ // 黑棋超过 12 个,不合法 if (black > 12) return; // 剩余格子不够放满 12 个黑棋,剪枝 if (25 - pos < 12 - black) return; // 25 个格子都处理完了 if (pos == 25) { if (black == 12) { // 此时白棋自动是 13 个 // 检查黑白双方都没有五连 if (check(board, -1) && check(board, 1)) { ans++; } } return; } int x = pos / 5; int y = pos % 5; // 方案1:这个位置放黑棋 board[x][y] = -1; if (check(board, -1)) solve(board, pos + 1, black + 1, ans);
#include<algorithm> #include<iostream> #include<vector> usingnamespace std; using vvector = vector<vector<int>>; intsolve(vvector &tree_m, vector<int> &weight_m, int u, vvector &tree_n, vector<int> &weight_n, int v){ if (weight_m[u] != weight_n[v]) return0; if (tree_m[u].empty() || tree_n[v].empty()) return1; int best = 0; for (int i = 0; i < tree_m[u].size(); i++) { int p = tree_m[u][i]; for (int j = 0; j < tree_n[v].size(); j++) { int q = tree_n[v][j]; best = max(best, solve(tree_m, weight_m, p, tree_n, weight_n, q)); } } return best + 1; } intmain(){ int m, n; cin >> m >> n;
for (int i = 0; i < m; i++) cin >> weight_m[i]; for (int i = 0; i < n; i++) cin >> weight_n[i];
vvector tree_m(m); vvector tree_n(n); for (int i = 0; i < m - 1; i++) { int u, v; cin >> u >> v; int p = max(u, v) - 1, q = min(u, v) - 1; tree_m[q].push_back(p); } for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; int p = max(u, v) - 1, q = min(u, v) - 1; tree_n[q].push_back(p); } int ans = solve(tree_m, weight_m, 0, tree_n, weight_n, 0); cout << ans << endl; return0; }
成绩统计
这题的关键在于把题目转化成一个带有单调性的判定问题。设 check(x) 表示在前 x 名同学中,是否已经能够选出 k 个成绩,使它们的方差严格小于 T。如果前 x 个人已经可行,那么前 x+1 个人显然也仍然可行,因为原来那 k 个人依旧可以被选到,所以答案具有明显的单调性,我们可以二分最小的前缀长度。
接下来考虑如何实现 check(x)。假设我们已经取出了前 x 个成绩,并将它们从小到大排序。此时有一个很重要的性质:如果要从中选出 k 个数,使得方差尽可能小,那么这 k 个数在排序后一定对应一段连续区间。直观理解也不难,如果当前选出的集合中间存在“空档”,那么把更远的数替换成中间的数,只会让整体更加集中,从而使方差不增。因此,判定时不需要枚举任意 k 个数,只需要枚举排序后所有长度为 k 的连续子段即可。
for (int i = 0; i < data.size(); i++) { s1 += data[i]; pre1.push_back(s1); s2 += 1LL * data[i] * data[i]; pre2.push_back(s2); }
for (int i = 1; i <= x + 1 - k; i++) { longlong S1 = pre1[i + k - 1] - pre1[i - 1]; longlong S2 = pre2[i + k - 1] - pre2[i - 1]; if (1LL * k * S2 - S1 * S1 < 1LL * k * k * t) returntrue; } returnfalse; }
intmain(){ int n, k; longlong t; cin >> n >> k >> t;
vector<int> grade(n, 0); for (int i = 0; i < n; i++) { cin >> grade[i]; }
int ans = -1; if (check(n, grade, k, t)) { int l = k, r = n; while (l < r) { int mid = (l + r) / 2; if (check(mid, grade, k, t)) r = mid; else l = mid + 1; } ans = l; }
#include<algorithm> #include<iostream> #include<queue> #include<unordered_set> #include<vector> usingnamespace std; using vvector = vector<vector<int>>; using project = pair<int, int>; intsolve(vvector &road, vector<int> &c, int begin, int end){ int n = road.size(); vector<int> vis(n, 0); vector<int> parent(n, -1); queue<int> q; q.push(begin); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 1; if (u == end) break; for (int i = 0; i < road[u].size(); i++) { int v = road[u][i]; if (vis[v] != 1) { q.push(v); parent[v] = u; } } } unordered_set<int> res; int cur = end; while (cur != -1) { res.insert(c[cur]); if (cur == begin) break; cur = parent[cur]; } return res.size(); } intmain(){ int n, q; cin >> n >> q; vector<int> c(n, 0); for (int i = 0; i < n; i++) { cin >> c[i]; } vvector road(n); for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; road[u - 1].push_back(v - 1); road[v - 1].push_back(u - 1); } vector<project> plan(q); for (int i = 0; i < q; i++) { int u, v; cin >> u >> v; plan[i] = {u - 1, v - 1}; } for (int i = 0; i < q; i++) { int ans = solve(road, c, plan[i].first, plan[i].second); cout << ans << endl; } return0; }