E. C+K+S

lyrrr發表於2024-11-21

E. C+K+S
很有意思的一個題。
什麼方案是合法的?一個入點連線到另一個圖的出點,並且這個出點mod k剛好比入點mod k多一(不嚴謹但是理解即可)
於是想到染色,染k個顏色,看有沒有兩張圖上顏色入點個數與對應顏色出點個數相同的匹配方案
先染色一張圖,因為不確定第二張圖要怎麼染色,所以可以隨便染色然後迴圈位移匹配check是否有合法方案。
如何匹配呢?
統計一個顏色入點和出點的個數。入點匹配的是其後一個點,出點匹配他的前一個點,所以匹配前需要先進行位移處理,方便匹配。
kmp可以做。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 5e5 + 10;
int n, k, m1, m2;
int a[2][N*3], kmp[N*3];

struct Graph{
    vector<int>E[N];
    int type[N], cnt[2][N];
    bool vis[N];

    void init() {
        for (int i = 0; i <= 2 * n; i++)
            E[i].clear(), cnt[1][i] = cnt[0][i] = vis[i] = 0;
    }

    void dfs(int u, int c) {
        vis[u] = 1;
        cnt[type[u]][c]++;
        for (int i: E[u]) {
            if (!vis[i]) dfs(i, (c + 1) % k);
        }
    }
} g[3];

void solve(){
    cin >> n >> k;
    g[1].init(); g[2].init();
    int cnt1 = 0, cnt2 = 0;
    for (int i = 1; i <= n; i++) {cin >> g[1].type[i]; cnt1+=g[1].type[i];}
    cin >> m1;
    for (int i = 1; i <= m1; i++) {
        int u, v; cin >> u >> v; 
        g[1].E[u].push_back(v);
    }
    for (int i = 1; i <= n; i++) {cin >> g[2].type[i]; cnt2+=g[2].type[i];}
    cin >> m2;
    for (int i = 1; i <= m2; i++) {
        int u, v; cin >> u >> v; 
        g[2].E[u].push_back(v);
    }
    g[1].dfs(1, 0); g[2].dfs(1, 0);
    // for(int i = 1; i <= k; i ++)
    //     cout <<"??1 "<< g[1].c1[i] << ' ' << g[1].c0[i] << endl;
    // for(int i = 1; i <= k; i ++)
    //     cout <<"??2 "<< g[2].c1[i] << ' ' << g[2].c0[i] << endl;
    bool x = 0;
    for (int i = 0; i < k; i++) {
        a[0][(i + 1)%k] = g[1].cnt[1][i], a[1][i] = g[1].cnt[0][(i + 1)%k];
    }
    for (bool t: {0, 1}) {
        a[t][k] = -1;
        for (int i = 0; i < k; i++)
            a[t][i + 1 + k] = a[t][i + 1 + k*2] = g[2].cnt[t][i];
    }
    for (int i = 1; i <= k*3; i++) {
        int j = kmp[i - 1];
        while(j && ((a[0][j] != a[0][i]) || (a[1][j] != a[1][i])))
            j = kmp[j - 1];
        if((a[0][j] == a[0][i]) && (a[1][j] == a[1][i]))
            j++;
        kmp[i] = j;
        if (i > k && j >= k) {
            x = 1; break;
        }
    }
    if (x || ((cnt1 == 0 && cnt2 == n) || (cnt1 == n && cnt2 == 0))) cout << "Yes" << endl;
    else cout << "NO" << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    cin >> T;
    while (T--)
        solve();
}
/*
1
4 2
1 1 1 1
4
1 2
2 3
3 4
4 1
0 0 0 0
6
1 2
2 1
1 3
3 1
1 4
4 1
*/