[51nod 1753] 相似子串

问题描述

两个字符串相似定义为:
1.两个字符串长度相等
2.两个字符串对应位置上有且仅有至多一个位置所对应的字符不相同
给定一个字符串,每次询问两个子串在给定的规则下是否相似。给定的规则指每次给出一些等价关系,如‘a'=’b',‘b'=’c'等,注意这里的等价关系具有传递性,即若‘a'=’b',‘b'=’c',则‘a'=’c'。

输入格式

第一行一个字符串s(1<=|s|<=300000)
第二行一个整数T(1<=T<=300000)
对于每次询问:
第一行5个整数k,l1,r1,l2,r2,表示有k个等价规则,询问的是子串[l1,r1],l2,r2
接下来k行每行两个连续的字符表示这两个字符等价。
此题中所有的字符均为小写字母。

输出格式

T行,若相似则输出“YES”否则输出“NO”

样例输入

abac
3
1 1 2 3 4
bc
1 1 2 3 4
ac
1 1 2 2 3
ac

样例输出

YES
YES
NO

解析

如果想要得到两个字符串是否相似,也就是说允许有一个字符不一样,那么不妨分为左边和右边两部分分别比较。如果两边完全一样,自然原来的两个字符串也是相似的;如果两边都不一样,那么不可能做到只有一个字符不一样,也就是说两个字符串不相似。当只有一边是一样的时候,就去验证不一样的那一半,这就是一个子问题了。

接下来的问题是如何比较两个字符串是否相等。可以用哈希来解决。由于会出现相同规则的更改,用并查集维护相同字母的关系,然后分字母进行哈希,最后计算时在合并即可。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
#define N 300002
using namespace std;
const int p=199999;
const int mod=1000000007;
int t,l,i,j,fa[30],k,l1,r1,l2,r2,hash[N][30],poww[N];
char s[N];
int id(char x)
{
    return (int)(x-'a'+1);
}
int find(int x)
{
    if(x!=fa[x]) fa[x]=find(fa[x]);
    return fa[x];
}
int Hash(int l,int r)
{
    int ans=0;
    for(int i=1;i<=26;i++){
        int tmp=(hash[r][i]-hash[l-1][i]*poww[r-l+1]%mod+mod)%mod;
        ans=(ans+tmp*(find(i)+1)%mod)%mod;
    }
    return ans;
}
signed main()
{
    cin>>s>>t;
    l=strlen(s);
    poww[0]=1;
    for(i=1;i<=l;i++) poww[i]=poww[i-1]*p%mod;
    for(i=1;i<=l;i++){
        for(j=1;j<=26;j++) hash[i][j]=hash[i-1][j]*p%mod;
        hash[i][id(s[i-1])]=(hash[i][id(s[i-1])]+1)%mod;
    }
    while(t--){
        cin>>k>>l1>>r1>>l2>>r2;
        for(i=1;i<=26;i++) fa[i]=i;
        for(i=1;i<=k;i++){
            char a,b;
            cin>>a>>b;
            if(find(id(a))!=find(id(b))) fa[find(id(a))]=find(id(b));
        }
        bool flag=1;
        while(l1<r1&&l2<r2){
            int mid1=(l1+r1)/2,mid2=(l2+r2)/2;
            int h1=Hash(l1,mid1),h2=Hash(mid1+1,r1),h3=Hash(l2,mid2),h4=Hash(mid2+1,r2);
            if(h1!=h3&&h2!=h4){
                flag=0;
                break;
            }
            else if(h1==h3&&h2==h4) break;
            else if(h1==h3) l1=mid1+1,l2=mid2+1;
            else r1=mid1,r2=mid2;
        }
        if(flag) puts("YES");
        else puts("NO");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LSlzf/p/11872986.html