C. Bipartize
枚举每个点的颜色,然后统计有多少条边的端点颜色相同,这就是要删除的点,取最小值即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int n, m;
cin >> n >> m;
vector<P> es;
rep(i, m) {
int u, v;
cin >> u >> v;
--u; --v;
es.emplace_back(u, v);
}
int ans = m;
rep(s, 1<<n) {
vector<int> col(n);
rep(i, n) col[i] = s>>i&1;
int now = 0;
for (auto [u, v] : es) {
if (col[u] == col[v]) now++;
}
ans = min(ans, now);
}
cout << ans << '\n';
return 0;
}
D. The Simple Game
博弈型dp
记 dp[i][v] 表示从第 \(i\) 轮时棋子位于点 \(v\) 这个状态开始时的赢家是否是 \(\mathrm{Alice}\)
转移顺序:从后往前
转移需要用到以下性质:
一个状态是必胜状态,当且仅当它至少有一个后继是必败状态
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
void solve() {
int n, m, k;
string s;
cin >> n >> m >> k >> s;
vector<vector<int>> to(n);
rep(i, m) {
int u, v;
cin >> u >> v;
--u; --v;
to[u].push_back(v);
}
vector dp(k*2+1, vector<int>(n));
rep(v, n) {
dp[k*2][v] = s[v] == 'A';
}
for (int i = k*2-1; i >= 0; --i) {
rep(v, n) {
dp[i][v] = 0;
for (int u : to[v]) {
if (!dp[i+1][u]) dp[i][v] = 1;
}
}
}
if (dp[0][0]) puts("Alice");
else puts("Bob");
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}
E. Wind Cleaning
把“同时把所有垃圾平移一格”的动态,用一个 \(\mathrm{bfs}\) 在状态空间上跑最短路。每个状态由一个矩形区域(表示“仍然可能留在棋盘上的初始格子下标范围”)和当前 \(T\) 的位置共同描述。\(\mathrm{bfs}\) 在这些状态中按步数扩展(每一步相当于把所有垃圾朝某个方向移动一次,等价于改变 T 的相对偏移),一旦“矩形中没有任何 # 原始格”就说明所有垃圾都已经消失,此时的步数就是最终答案。
简单来说就是不断裁剪包含所有垃圾的最小矩形框,然后利用运动的是相互,保持垃圾不动,移动高桥的位置
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int h, w;
cin >> h >> w;
vector<string> s(h);
rep(i, h) cin >> s[i];
int si = 0, sj = 0;
rep(i, h)rep(j, w) if (s[i][j] == 'T') si = i, sj = j;
using S = tuple<int, int, int, int, int, int>;
map<S, int> dist;
queue<S> q;
auto push = [&](int li, int ri, int lj, int rj, int ti, int tj, int d) {
li = max(li, ti-si); ri = min(ri, h+(ti-si));
lj = max(lj, tj-sj); rj = min(rj, w+(tj-sj));
if (li <= ti and ti < ri and lj <= tj and tj < rj) {
if (s[ti][tj] == '#') return;
}
S st(li, ri, lj, rj, ti, tj);
if (dist.count(st)) return;
dist[st] = d;
q.emplace(st);
};
push(0, h, 0, w, si, sj, 0);
while (q.size()) {
int d = dist[q.front()];
auto [li, ri, lj, rj, ti, tj] = q.front(); q.pop();
{
int cnt = 0;
for (int i = li; i < ri; ++i) {
for (int j = lj; j < rj; ++j) {
if (s[i][j] == '#') cnt++;
}
}
if (cnt == 0) {
cout << d << '\n';
return 0;
}
}
push(li, ri, lj, rj, ti-1, tj, d+1);
push(li, ri, lj, rj, ti+1, tj, d+1);
push(li, ri, lj, rj, ti, tj-1, d+1);
push(li, ri, lj, rj, ti, tj+1, d+1);
}
puts("-1");
return 0;
}
F. Not Adjacent
折半搜索
发现两边还是有 \(30\) 个数,但注意到每边最多取到 \(15\) 个数,所以直接搜就行
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
rep(i, n) cin >> a[i];
auto enumerate = [&](int l, int r) {
vector<int> d0 = {0}, d1 = {0};
for (int i = l; i < r; ++i) {
vector<int> d2 = d1;
for (int x : d0) d2.push_back((x+a[i])%m);
swap(d0, d1);
swap(d1, d2);
}
return d1;
};
ll ans = 0;
int c = n/2;
rep(ci, 2) {
auto dl = enumerate(0, c-ci);
auto dr = enumerate(c+1+ci, n);
sort(dr.begin(), dr.end());
for (int x : dl) {
if (ci) x += a[c], x %= m;
int y = (m-x)%m;
int l = lower_bound(dr.begin(), dr.end(), y) - dr.begin();
int r = upper_bound(dr.begin(), dr.end(), y) - dr.begin();
ans += r-l;
}
}
cout << ans << '\n';
return 0;
}
另外,不相邻子序列的数量其实是斐波那契数列(虽然用了这个也没有变的很快)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
rep(i, n) cin >> a[i];
vector<int> fib(n+1, 1);
for (int i = 2; i <= n; ++i) fib[i] = fib[i-1]+fib[i-2];
auto enumerate = [&](int l, int r) -> vector<int> {
if (l >= r) return {0};
int w = r-l;
vector<int> res(fib[w+1]);
for (int s = 1, fi = 1; s < fib[w+1]; ++s) {
if (fib[fi+1] <= s) fi++;
res[s] = (a[r-fi]+res[s-fib[fi]])%m;
}
return res;
};
ll ans = 0;
int c = n/2;
rep(ci, 2) {
auto dl = enumerate(0, c-ci);
auto dr = enumerate(c+1+ci, n);
sort(dr.begin(), dr.end());
for (int x : dl) {
if (ci) x += a[c], x %= m;
int y = (m-x)%m;
int l = lower_bound(dr.begin(), dr.end(), y) - dr.begin();
int r = upper_bound(dr.begin(), dr.end(), y) - dr.begin();
ans += r-l;
}
}
cout << ans << '\n';
return 0;
}
G. Takahashi's Expectation 2
二进制分组+块间合并
直接看StarSilk的题解
浙公网安备 33010602011771号