[USACO23JAN] Find and Replace S 题解

首先,我们称初始串为 $s$,目标串为 $t$,接下来把每个的 $s_i$ 向 $t_i$ 连边,不难发现,每个点出度最多为 $1$,超过 $1$ 的话就输出 $-1$。那么这张图里的每个节点只可能有多个节点连向他,他最多连向一个节点。

接下来我们对每个没遍历过的节点一遍深度优先搜索(类似建图,我们把一种字母称为一个节点),新建一个颜色,用 $ct_i=1$ 表示 $i$ 颜色的那些点是环且没有其它点连向环中节点,反之 $ct_i=0$。我们考虑 $i$ 颜色的那些点是环但有其它点连向环中节点的那种情况,假设 $u$ 连向了环中的 $v$ 节点,那么必定可以把所有 $v$ 代表的字母变成 $u$ 代表的字母,破环成链,这样就可以把连向 $v$ 的环中节点所代表的的字母都变成 $v$ 代表的字母,以此类推,最后再把 $u$ 代表的字母替换成 $v$ 代表的字母。

这是,如果存在有 $ct_i=1$,那么就证明有单独的环,需要先把任意节点替换成其它的破环成链才行,所以再用 $h_i$ 记录 $i$ 是否是非环中节点(包括自环),如果存在有 $ct_i=1$ 且所有 $h_i$ 都是 $1$,那么答案是 $-1$,否则是边数加上 $\sum ct_i$。

#include <bits/stdc++.h>
#define L(i, a, b) for(int i = a; i <= b; i++)
#define R(i, a, b) for(int i = a; i >= b; i--) 
using namespace std;
const int N = 1e5 + 10;
int n, cnt, bo, ans;
int e[N], vis[52], h[52], ct[52], t[52][52];//vis[i]表示i节点的颜色
char a[N], b[N];
void Init(){
    memset(t, 0, sizeof(t));
    memset(h, 0, sizeof(h));
    memset(ct, 0, sizeof(ct));
    memset(e, -1, sizeof(e));
    memset(vis, -1, sizeof(vis));
}
int Get(char c){
    return c >= 'a'? c - 'a' + 26 : c - 'A';
}
int Dfs(int u, int col){
    vis[u] = col;
    if(e[u] != -1){
        if(vis[e[u]] == col){
            int v = e[u]; e[u] = -1;
            ct[col] = 1, h[u] = 1;
            return v;
        }
        if(~vis[e[u]]){
            ct[vis[e[u]]] = 0, e[u] = -1;
            return 52;
        }
        int ret = Dfs(e[u], col);
        if(ret == 52) ct[vis[e[u]]] = 0;
        e[u] = -1;
        if(~ret){
            if(ret != 52) h[u] = 1;
            if(ret != u) return ret != u? ret : 52;
        }
    } 
    return -1;
}
void Solve(){
    scanf("%s%s", a + 1, b + 1);
    cnt = bo = ans = 0;
    n = strlen(a + 1), Init();
    L(i, 1, n)
        t[Get(a[i])][Get(b[i])] = 1;
    L(i, 0, 51){
        int k = -1;
        L(j, 0, 51){
            if(t[i][j]){
                if(~k){printf("-1\n"); return;}
                k = j;
            }
        }
        if(k == i) h[i] = 1;
        else if(~k) ans++, e[i] = k;
    }
    L(i, 0, 51) if(vis[i] == -1) Dfs(i, i);
    L(i, 0, 51){
        if(!h[i]) bo = 1;
        cnt += ct[i];
    }
    if(cnt && !bo){printf("-1\n"); return;}
    ans += cnt, printf("%d\n", ans);
}
int main(){
    int T; scanf("%d", &T);
    while(T--) Solve();
    return 0;
}
posted @ 2023-02-05 22:23  徐子洋  阅读(45)  评论(0)    收藏  举报  来源