abc211
C - chokudai 559
询问长为 \(1e5\) 的给定字符串中,子序列 chokudai 的数量
简单dp。目标子序列没有重复元素,非常方便
D - Number of Shortest paths 755
边权为1,问最短路数量。bfs最短路径数模板题
普通的bfs 普通的队列
E - Red Polyomino 1823
在 n×n 黑白矩阵中,问把某 k 个白格染成红色且红色区域连通的方案数。\(n,k\le 8\)
可以dp(轮廓线?)但太麻烦了。
容易发现状态数小于 \(C_{n^2}^k=4426165368\),呃,好多啊!但实际上的状态数(不知道咋数学证明)远小于此,爆搜就能过
注意每一步是整个棋盘的状态,而不是一格
值得学习的是,可以不记录搜过的状态,染红并dfs之后染黑禁掉这格即可,这样就保证了每个状态只搜一次。代码飞快,12ms
#include <bits/stdc++.h>
using namespace std;
const int dx[] = {0,0,-1,1}, dy[] = {-1,1,0,0};
int n, k, ans;
string g[8];
void dfs(int k) {
if (!k) return ans++, void();
vector<pair<int, int>> ve;
for (int x = 0; x < n; x++) {
for (int y = 0; y < n; y++) {
if (g[x][y] == '.') {
bool conn = false; //连通性 周围有红色才搜
for (int i = 0; i < 4; i++) {
int xx = x + dx[i], yy = y + dy[i];
if (xx < 0 || xx >= n || yy < 0 || yy >= n)
continue;
if (g[xx][yy] == '@')
conn = true;
}
if (conn) {
g[x][y] = '@'; //染红
dfs(k - 1);
g[x][y] = '#'; //禁掉
ve.push_back({x, y});
}
}
}
}
for (auto [x, y] : ve)
g[x][y] = '.'; //这里要恢复现场
}
int main() {
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> g[i];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (g[i][j] == '.') {
g[i][j] = '@'; //染红
dfs(k - 1); //已经染了一个了
g[i][j] = '#'; //已经搜过g[i][j]='@'的所有状态了,禁掉
}
}
}
cout << ans;
return 0;
}
F - Rectilinear Polygons 2350
给定 \(n\) 个简单多边形(边界均水平或竖直,不一定凸)的所有顶点(输入的相邻顶点属于同一条边)和 \(q\) 个点,问每个点属于多少个多边形。范围和值域都是 \(1e5\)
一个简单的类似扫描线的东西,开个普通树状数组维护一列差分,实现单点 +1/-1 还有查询区间和,从左到右每次考虑一列即可
亮点:如何确定哪些点要 +1 哪些要 -1?画图发现每个多边形左下角(及在 x 最小的前提下 y 最小)的那个顶点必是 +1,其它点是 -1,+1,-1,+1,...
写了个 \([0,N-1]\) 的树状数组
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5;
int tr[N];
void add(int p, int v) {
while (p < N) {
tr[p] += v;
p |= (p + 1);
}
}
int ask(int p) {
int s = 0;
while (p >= 0) {
s += tr[p];
p = (p & (p + 1)) - 1;
}
return s;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<vector<pair<int, int>>> modify(N);
while (n--) {
int m;
cin >> m;
vector<pair<int, int>> corners(m);
for (auto &[x, y] : corners)
cin >> x >> y;
auto p = min_element(corners.begin(), corners.end()) - corners.begin(); //左下角的顶点
for (int i = 0; i < m; i++) {
auto [x, y] = corners[(p + i) % m];
modify[x].push_back({y, i % 2 ? -1 : 1});
}
}
int q;
cin >> q;
vector<vector<pair<int, int>>> points(N);
for (int i = 0; i < q; i++) {
int x, y;
cin >> x >> y;
points[x].push_back({y, i});
}
vector<int> ans(q);
for (int x = 0; x < N; x++) {
for (auto [y, v] : modify[x])
add(y, v);
for (auto [y, i] : points[x])
ans[i] = ask(y);
}
for (auto x : ans) {
cout << x << '\n';
}
return 0;
}

浙公网安备 33010602011771号