E. C+K+S

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
*/
posted @ 2024-11-21 11:29  lyrrr  阅读(4)  评论(0编辑  收藏  举报