题解:CF1299D Around the World
Priestess_SLG · · 题解
這也能做嗎.jpg
套路的考慮先求出圖的任意一個 DFS 生成樹,然後結合綫性基來維護答案。具體的,任意求出圖的一個 DFS 樹后記
因此題目中的限制條件等價於:所有當前和點
然後把點
因此:刪除點
如果塊内部本身合法就考慮她和
- 如果刪除了這條邊那麽這個塊和
1 號節點斷開,什麽都不用加入全局綫性基。 - 如果保留這條邊,那麽點
1 可以進入這個塊,因此把塊内綫性基B 合并到全局綫性基中即可。
如果有兩條邊設她們分別是
- 兩條邊都刪除:什麽也不用加入。
- 只保留一條邊:點
1 可以進入這個塊,只需要加入綫性基B 即可。注意有兩種保留一條邊的方法。 - 保留兩條邊:除了
B 以外還需要加入三元環的貢獻即 XORa\oplus b\oplus c 這個環。此時如果a\oplus b\oplus c 插入不了B 這個綫性記則兩條邊都保留這個操作本身就是非法的。
現在每個連通塊都被壓縮成了兩三個網全局綫性基中加入哪些數的選擇。問題只剩下如何把不同的連通塊合起來處理了。此時顯然不能只保證每個塊内部合法,因爲不同的塊之間也可以凑出 XOR 為
記
- 對只有一個便連向
1 的塊,轉移要麽仍然為S 要麽從S 變爲merge(S,B) 。 - 對於有兩條邊的塊,轉移方式有下面的三種:
-
需要處理一下綫性基無法插入也就是轉移非法的情況。
處理完所有連通塊后,答案可以被表示爲
正確性顯然是對的,時間複雜度懶得分析了,反正能過。
:::success[Code]
namespace lowspeed_song {
inline void init() {
}
struct Basis {
int b[5];
inline Basis() { memset(b, 0, sizeof b); }
inline int ins(int x) {
for (int i = 4; ~i; --i) if (x >> i & 1) {
if (b[i]) x ^= b[i];
else return b[i] = x, 1;
} return 0;
}
inline int getmask() const {
int s = 1;
for (int i = 0; i < 5; ++i) if (b[i]) {
int t = s;
for (int j = 0; j < 32; ++j)
if (s >> j & 1) t |= 1 << (j ^ b[i]);
s = t;
} return s;
}
};
vector<pair<int, int>> adj[N];
int w_[N], vis[N], dep[N], xr[N], f[N], g[N];
int trans[710][710], idx;
Basis state[N];
inline void sol([[maybe_unused]]int __testcase_id) {
idx = 1;
map<int, int> mp; mp[1] = 0;
for (int i = 0; i < idx; ++i)
for (int j = 1; j < 32; ++j) {
Basis t = state[i];
if (!t.ins(j)) continue;
int s = t.getmask();
if (!mp.count(s)) mp[s] = idx, state[idx++] = t;
}
memset(trans, -1, sizeof trans);
for (int i = 0; i < idx; ++i)
for (int j = 0; j < idx; ++j) {
Basis t = state[i];
int ok = 1;
for (int k = 0; k < 5; ++k)
if (state[j].b[k] && !t.ins(state[j].b[k])) ok = 0;
if (ok) trans[i][j] = mp[t.getmask()];
}
int n, m; cin >> n >> m;
memset(w_, -1, sizeof w_);
while (m--) {
int u, v, w; cin >> u >> v >> w;
adj[u].emplace_back(v, w), adj[v].emplace_back(u, w);
if (u == 1) w_[v] = w;
if (v == 1) w_[u] = w;
} f[0] = 1;
for (int i = 2; i <= n; ++i) if (!vis[i]) {
Basis basis;
int ok = 0;
vector<pair<int, int>> vec;
function<void(int, int)> dfs = [&](int u, int fa) {
vis[u] = 1, dep[u] = dep[fa] + 1;
if (~w_[u]) vec.emplace_back(u, w_[u]);
for (auto &[v, w] : adj[u]) if (v != fa && v != 1) {
if (!vis[v]) xr[v] = xr[u] ^ w, dfs(v, u);
else if (dep[v] < dep[u] && !basis.ins(xr[u] ^ xr[v] ^ w)) ok = 1;
}
};
dfs(i, 0);
vector<pair<int, int>> vec_ = {{0, 1}};
if (!ok) {
int b = mp[basis.getmask()];
if (vec.size() == 1) vec_.emplace_back(b, 1);
else if (vec.size() == 2) {
vec_.emplace_back(b, 2);
int u = vec[0].first, v = vec[1].first, w = 0;
for (auto &[vv, c] : adj[u]) if (vv == v) { w = c; break; }
Basis T = basis;
if (T.ins(vec[0].second ^ vec[1].second ^ w)) vec_.emplace_back(mp[T.getmask()], 1);
}
}
for (int i = 0; i < idx; ++i) g[i] = 0;
for (int i = 0; i < idx; ++i) for (auto &[j, k] : vec_)
if (~trans[i][j]) g[trans[i][j]] = (g[trans[i][j]] + f[i] * k) % mod;
for (int i = 0; i < idx; ++i) f[i] = g[i];
}
int res = 0;
for (int &i : f) res = (res + i) % mod;
cout << res << '\n';
}
} // namespace lowspeed_song
:::