CF2024

CF2024E C-K-S

两个强连通图,然后所有环长都被 \(k\) 整除,这个条件还是很强的。具体来说,对于 \(u \to v\) 的所有路径,他们模 \(k\) 一定同余。进一步地,如果记 \(1 \to u\) 的距离模 \(k\)\(tp_u\),那么 \(u \to v\) 的路径长是 \(tp_v - tp_u\)\(k\)
然后先把一边全是出点一边全是入点的判掉,这样中间肯定也会成环。比方说对于 \(a \to b \leadsto c \to d \leadsto a\) 的这样一个环,其中 \(a, d\) 在前面那个图里,\(b, c\) 在后面那个图里,一定有 \((tp_c - tp_b) + (tp_a - tp_d) + 2 \equiv (tp_a - tp_b) + (tp_c - tp_d) + 2 \equiv 0 \pmod k\)。这里的 \(tp\) 是分别对对应的两个图而言的。
然后就卡住了。实际上再取另一对 \(a', b'\) 让它们与 \(c, d\) 成环,可以发现,所有 \(a \to b\) 有连边的 \(tp_a - tp_b\) 一定都同余,同理所有 \(c \to d\) 有连边的 \(tp_c - tp_d\) 也一定都同余。
貌似就做完了啊。我们记 \(cnt_{0/1, 0/1, i}\) 表示前面/后面的图,入点/出点,有多少个 \(tp_u = i\) 的点。枚举 \(s \equiv tp_a - tp_b(0 \le s < k)\),此时 \(tp_c - tp_d \equiv -2-s := t\)。那么我们只要验证模 \(k\) 的 cyclic 意义下,\(\forall i,cnt_{0,1,i + s} = cnt_{1,0,i}\)\(\forall j, cnt_{1, 1, j + t} = cnt_{0, 0, j}\),哈希即可。

Code
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N = 4e5 + 5;
const ull P = 524287;
ull pw[N];
int n, k;
struct Graph{
    bool a[N]; // 0 in 1 out
    int tp[N], cnt[2][N];
    ull hsh[2][2 * N];
    vector<int> e[N];
    bool check(bool op){ 
        for(int i = 1; i <= n; ++i) 
            if(a[i] != op) 
                return 0; 
        return 1;
    }
    void clear(){ 
        for(int i = 1; i <= n; ++i) e[i].clear(), tp[i] = -1;
        for(int j : {0, 1}){
            for(int i = 0; i < k; ++i) cnt[j][i] = 0;
        }
    }
    void adde(int u, int v){ e[u].push_back(v); }
    void dfs(int u, int d){
        if(tp[u] != -1) return;
        tp[u] = d;
        cnt[a[u]][tp[u]]++;
        for(int v : e[u]){
            dfs(v, (d + 1) % k);
        }
    }
    void init(){
        for(int j : {0, 1}){
            hsh[j][0] = cnt[j][0];
            for(int i = 1; i < 2 * k; ++i){
                hsh[j][i] = hsh[j][i - 1] * P + cnt[j][i % k];
            }
        }
    }
    ull get(bool op, int l, int r){
        if(l == 0) return hsh[op][r];
        return hsh[op][r] - pw[r - l + 1] * hsh[op][l - 1];
    }
}g[2];
istream& operator >> (istream &in, Graph &b){
    for(int i = 1; i <= n; ++i) cin >> b.a[i];
    int m; cin >> m;
    for(int i = 1; i <= m; ++i){
        int u, v; cin >> u >> v;
        b.adde(u, v);
    }
    return in;
}
void solve(){
    cin >> n >> k;
    for(int j : {0, 1}){
        g[j].clear(); 
        cin >> g[j];
        g[j].dfs(1, 0);
        g[j].init();
    }
    for(int j : {0, 1}){
        if(g[0].check(j) && g[1].check(j ^ 1)) 
            return cout << "Yes\n", void();
    }
    for(int s = 0; s < k; ++s){
        int t = ((-2 - s) % k + k) % k;
        if(g[1].get(0, 0, k - 1) == g[0].get(1, s, s + k - 1) && 
           g[0].get(0, 0, k - 1) == g[1].get(1, t, t + k - 1))
            return cout << "Yes\n", void();
    }
    cout << "No\n";
}
int main(){
    cin.tie(nullptr)->sync_with_stdio(0);
    pw[0] = 1;
    for(int i = 1; i <= 4e5; ++i) pw[i] = pw[i - 1] * P;
    int T; cin >> T;
    while(T--) solve();
    return 0;
}
posted @ 2025-11-28 10:29  Hengsber  阅读(6)  评论(0)    收藏  举报