1001 造花(简单版)
如果删去一个点后能分成两个菊花图,那么删去的点度数一定为2。如果能成功分成两个菊花图,那么原来的图中最多只有 5 个度数大于等于 2 的点(被删去的点、与被删去的点直接相连的两个点、两个菊花图中与剩余点直接相连的点)。
所以只需要检查每一个度数为 2 的点删去后是否能构成两个菊花图,检查一次的时间复杂度为 ,最多不会超过 5 次检查,所以总时间复杂度也是
。
#include <bits/stdc++.h>
using namespace std;
struct dsu {
vector<int> v;
dsu(int n): v(n + 1) {
for (int i = 0; i <= n; i++) v[i] = i;
}
int find(int x) { return x == v[x] ? x : v[x] = find(v[x]); }
void unit(int x, int y) { v[find(x)] = find(y); }
};
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
bool solve() {
int n = read();
vector<set<int>> e(n + 1);
for (int i = 1; i < n; i++) {
int u = read(), v = read();
e[u].insert(v), e[v].insert(u);
}
auto check = [&](int t) {
bool flag = true;
dsu d(n);
for (int i = 1; i <= n; i++)
for (int j : e[i])
if (i != t && j != t) d.unit(i, j);
// 将一个图中的点用并查集连在一起
map<int, vector<int>> mp;
for (int i = 1; i <= n; i++)
if (i != t) mp[d.find(i)].push_back(i);
// 将一个图中的所有结点编号全部存到一起
for (int v : e[t]) e[v].erase(t); // 删除节点 t 后再进行判断
for (auto [a, b] : mp) {
int cnt = 0;
for (int x : b) if (e[x].size() == 1) cnt++;
if (b.size() - cnt > 1) flag = false;
// 最多有一个节点度数不为 1
}
for (int v : e[t]) e[v].insert(t); // 重新加入节点 t
return flag;
}; // 检查是否构成两个菊花图
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (e[i].size() == 1) continue;
if (++cnt > 5) break; // 超过 5 个度数大于等于 2 的节点
if (e[i].size() == 2 && check(i)) return true;
}
return false;
}
int main() {
int t = read();
while (t--) {
puts(solve() ? "Yes" : "No");
}
return 0;
}
1003 飞车狂飙
假设飞车从 (0, 0) 出发,初始时方向朝右,用一个 set 存经过的点的坐标,判断是否有重叠,最后看是否成环(回到起点且方向相同)。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int t, n;
char str[N];
set<pair<int, int>> s;
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
// 分别表示向右、上、左、下方向移动一个单位
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int main() {
t = read();
while (t--) {
n = read();
scanf("%s", str);
s.clear();
int d = 0; // 用来记录方向
s.insert({0, 0});
int x = 0, y = 0, flag = 0;
for (int i = 0; i < n; i++) {
if (str[i] == 'L') d = (d + 1) % 4;
else if (str[i] == 'R') d = (d + 3) % 4;
int xx = x + dx[d], yy = y + dy[d];
if (i != n - 1 && s.count({xx, yy})) flag = 1; // 之前已经经过了这个点,形成了重叠
else s.insert({xx, yy});
x = xx, y = yy;
}
if (flag) {
puts("-1");
} else {
if (x == 0 && y == 0 && d == 0) puts("1"); // 回到原点且方向相同
else puts("0");
}
}
return 0;
}
1004 不醒人室
按照题意模拟:遍历每一个休息的时间,更新不困的状态的时间,判断是否会在课上休息或者课上处于很困的状态。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int t, n, m;
struct { int b, e; } cla[N];
struct { int s, t; } sle[N];
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
void solve() {
n = read(), m = read();
cla[0] = {0, 0};
for (int i = 1; i <= n; i++) cla[i].b = read(), cla[i].e = read();
for (int i = 1; i <= m; i++) sle[i].s = read(), sle[i].t = read();
int ok = 0, p = 1;
for (int i = 1; i <= m; i++) {
if (cla[p - 1].e <= sle[i].s && sle[i].t <= cla[p].b) {
ok = max(ok, sle[i].t + 2 * (sle[i].t - sle[i].s)); // 更新清醒时间
} else {
puts("No");
return;
}
while (p + 1 <= n && ok >= cla[p].e && cla[p].b < sle[i + 1].t) p++;
}
puts("Yes");
}
int main() {
t = read();
while (t--) solve();
return 0;
}
1005 交通管控
根据 k 的范围,我们可以想到状压dp。将每一种字符串转换成对应的一个整数(总共不超过 种)。从头到尾遍历每一个字符串 s,根据字符串 s 对现有的状态进行修改并且更新各个状态的数量。
#include <stdio.h>
#include <vector>
#include <functional>
using namespace std;
const int pow3[11] = {1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049};
int M;
char s[11];
struct modint {
int x;
bool is_zero; // 记录个数是真的为 0 还是是模数的倍数
modint(): x(0), is_zero(true) {}
modint(int _x): x(_x), is_zero(x == 0){}
void operator += (const modint & a) {
if (a.is_zero) return;
x += a.x;
if (x >= M) x -= M;
is_zero = false;
return;
}
};
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int main() {
int t = 1;
t = read();
while (t--) {
int n, k;
n = read(), k = read(), M = read();
vector<modint> dp(pow3[k]);
dp[0] = modint(1);
for (int i = 0; i < n; i++) {
scanf("%s", s);
function<int(int)> calc = [&](int x) {
int num = 0;
for (int i = 0; i < k; i++) {
int tt = (x / pow3[k - i - 1]) % 3;
if (s[i] == '+') tt = (tt + 1) % 3;
else if (s[i] == '-') tt = (tt + 2) % 3;
num = num * 3 + tt;
} // 将字符串转换成整数
return num;
};
vector<modint> tmp = dp;
for (int j = 0; j < pow3[k]; j++) tmp[calc(j)] += dp[j];
dp = tmp;
}
for (int i = 0; i < pow3[k]; i++) {
if (!dp[i].is_zero) {
for (int j = k - 1; j >= 0; j--) {
int tt = (i / pow3[j]) % 3;
putchar(tt + 'A');
} // 将整数转换成字符串
printf(" %d\n", dp[i].x);
}
}
}
return 0;
}