P3485 [POI2009] BAJ-The Walk of Bytie-boy 题解
暴力没前途,怎么可能,直接喜提最劣解。
思路#
考虑一个最基本做法。
设
然后对每个二元组广搜。
拓展时暴力搜
这样是
但是我们会感到奇怪。
明明只有
发现最大的时间损耗在我们的入边有可能和出边匹配过。
这样就有了很多无效的匹配。
怎么办。
使用 bitset!
我们将能匹配的出边用 bitset 存,每个点没有匹配过的点也用 bitset 存。
寻找的时候把两个与一下,找到里面的所有点即可。
时间复杂度降为了:
Code#
/*
! 如果没有天赋,那就一直重复
! Created: 2024/06/26 09:26:19
*/
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
// #define int long long
#define mp(x, y) make_pair(x, y)
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
inline void JYFILE19();
using i64 = long long;
using u64 = unsigned long long;
using PII = pair<int, int>;
bool ST;
const int N = 410;
const int M = 60010;
const int mod = 998244353;
int n, m, d, ct, tt, tp, st[M], f[N][N], head[N], fead[N];
pair<PII, int> nt[N][N];
vector<int> res;
template<int T> struct Bitset {
u64 v[T / 64 + 10], n, all;
Bitset() { n = T / 64 + 1, all = -1; }
inline void clr() { memset(v, 0, sizeof v); }
inline void get() {
res.clear();
fro(i, 0, n) {
if (v[i]) {
auto x = v[i], lg = 1ull;
while (x) lg = __lg(x), res.eb(lg + i * 64), x -= (1ull << lg);
}
}
}
inline void set(int x) { v[x>>6] ^= 1ull<<(x&63); }
inline void operator&=(const Bitset<T> &tmp) { fro(i, 0, n) v[i] &= tmp.v[i]; }
};
Bitset<401> w, g[27], vs[401];
struct edge {
int to, nxt, val;
} e[M << 1], p[M << 1];
inline void add(int x, int y, int z) {
e[++ct] = {y, head[x], z}, head[x] = ct;
p[++tt] = {x, fead[y], z}, fead[y] = ct;
}
inline void sol(int l, int r) {
int L, R;
tie(L, R) = nt[l][r].x;
st[++tp] = nt[l][r].y;
if (L == l && r == R) return;
sol(L, R);
}
signed main() {
JYFILE19();
cin >> n >> m;
fro(i, 1, m) {
int x, y; char c;
cin >> x >> y >> c;
add(x, y, c - 'a');
}
queue<PII> q;
fro(i, 1, n) fro(j, 1, n) if (i != j) vs[i].set(j);
fro(i, 1, n) {
for (int j = head[i]; j; j = e[j].nxt) {
if (f[i][e[j].to] == 0) {
f[i][e[j].to] = 1;
nt[i][e[j].to] = {{i, e[j].to}, e[j].val};
vs[i].set(e[j].to);
q.emplace(i, e[j].to);
}
}
}
fro(i, 1, n) {
for (int j = head[i]; j; j = e[j].nxt)
for (int k = head[e[j].to]; k; k = e[k].nxt) {
if (f[i][e[k].to] == 0 && e[j].val == e[k].val) {
f[i][e[k].to] = 2;
nt[i][e[k].to] = {{i, e[k].to}, e[k].val};
vs[i].set(e[k].to);
q.emplace(i, e[k].to);
}
}
}
while (q.empty() == 0) {
int l, r;
tie(l, r) = q.front(), q.pop();
fro(i, 0, 25) g[i].clr();
for (int i = head[r]; i; i = e[i].nxt) {
g[e[i].val].set(e[i].to);
}
for (int i = fead[l]; i; i = p[i].nxt) {
w = vs[p[i].to], w &= g[p[i].val], w.get();
for (auto j : res) {
f[p[i].to][j] = f[l][r] + 2;
nt[p[i].to][j] = {{l, r}, p[i].val};
vs[p[i].to].set(j);
q.emplace(p[i].to, j);
}
}
}
cin >> d;
for (int i = 1, las = 0; i <= d; i++) {
int x; cin >> x;
if (i > 1) {
if (f[las][x]) {
cout << f[las][x] << " ", tp = 0, sol(las, x);
fro(i, 1, tp) cout << (char)(st[i] + 'a');
if (f[las][x] % 2 == 0) cout << (char)(st[tp] + 'a');
pre(i, tp, 2) cout << (char)(st[i - 1] + 'a');
cout << "\n";
} else {
cout << -1 << "\n";
}
}
las = x;
}
return 0;
}
bool ED;
inline void JYFILE19() {
// freopen("", "r", stdin);
// freopen("", "w", stdout);
srand(random_device{}());
ios::sync_with_stdio(0), cin.tie(0);
double MIB = fabs((&ED - &ST) / 1048576.), LIM = 32;
cerr << "MEMORY: " << MIB << endl, assert(MIB <= LIM);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)