[CF985F] Isomorphic Strings

题目描述

You are given a string s of length n consisting of lowercase English letters.

For two given strings s and t , say SS is the set of distinct characters of s and T is the set of distinct characters of t . The strings s and t are isomorphic if their lengths are equal and there is a one-to-one mapping (bijection) ffbetween S and T for which f((s_{i}))=(t_{i}). Formally:

  1. f((s_{i}))=(t_{i})​ for any index i ,
  2. for any character there is exactly one character that f(x)=y ,
  3. for any character there is exactly one character that f(x)=y .

For example, the strings "aababc" and "bbcbcz" are isomorphic. Also the strings "aaaww" and "wwwaa" are isomorphic. The following pairs of strings are not isomorphic: "aab" and "bbb", "test" and "best".

You have to handle mm queries characterized by three integers x,y,lenx,y,len ( 1<=x,y<=n-len+1 ). For each query check if two substrings s[x... x+len−1] and s[ y... y+len−1] are isomorphic.

输入输出格式

输入格式:

The first line contains two space-separated integers n and m ( 1<=n<=2 * 10^5 , 1<=m<=2* 10^5 ) — the length of the string ss and the number of queries.

The second line contains string ss consisting of nn lowercase English letters.

The following mm lines contain a single query on each line: x_{i}xi​ , y_{i}yi​ and len_{i}leni​ ( 1<=xi​,yi​<=n , 1<=leni​<=n−max(xi​,yi​)+1 ) — the description of the pair of the substrings to check.

输出格式:

For each query in a separate line print "YES" if substrings s[xi​... xi​+leni​−1] and s[yi​... yi​+leni​−1] are isomorphic and "NO" otherwise.

输入输出样例

输入样例#1:

7 4
abacaba
1 1 1
1 4 2
2 1 3
2 4 3

输出样例#1:

YES
YES
NO
YES

说明

The queries in the example are following:

  1. substrings "a" and "a" are isomorphic: f ( a )=a ;
  2. substrings "ab" and "ca" are isomorphic: f ( a )=c , f ( b )=a ;
  3. substrings "bac" and "aba" are not isomorphic since f(b) and f ( c ) must be equal to a at same time;
  4. substrings "bac" and "cab" are isomorphic: f ( b )=c , f ( a )=a , f ( c )=b .

题解

题目大意:给你一个完整字符串,长度为n,接下来有m个询问,每个询问包括三个关键字x,y,len起点1,起点2和长度,我们需要判断以x为起点长度为len的字串和以y为起点的长度为len的子串的映射是否合法,若合法输出(YES),否则输出(NO)

题意应该很清晰
题目要求,若映射合法,要求映射唯一,即x子串中的字母对应的映射应该在y中可以找到,同时y子串中的字母也应该可以在x子串中找到对应的元素
所以我们可以对原子串的每个字母分别hash.

inline void Hash() {
 for(lol i=1;i<=n;i++) 
	 for(lol j=1;j<=26;j++)
	  hash[i][j]=(hash[i-1][j]*base%mod+(lol)(s[i]==('a'+j-1)))%mod; 
}

其中hash[i][j]数组代表原子串的第i位,字母是j的hash值
然后hash的基本操作就是把字符串变成一个进制数,所以我们可以预处理一下这个进制数上第i位的权值

inline void init() { 
sum[0]=1;
 for(lol i=1;i<=n;i++) 
	sum[i]=sum[i-1]*base%mod; 
}

那么,我们要怎么比较这两个子串是否相等呢,假设把k进制换成10进制
原字符串对应的hash值为12345
x=2,len=3;
我们要求的是234的hash值=hash[1234]-hash[1](*)sum[3] (10进制下的sum[3]=1000,可以看成在1后面补了3个0)
那么应该很好理解了,这个子串对应的hash值就是hash[x+len-1]-hash[x-1](*)sum[len]

y子串和x一样,然后判断一下每个字符的hash值相不相等就好了

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std;
typedef long long lol;
const lol base=131,mod=1e9+7;
lol read() {
    lol ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') {ans=(ans<<1)+(ans<<3)+i-'0'; i=getchar();}
    return ans*f;
}
lol l,r,len,n,m;
char s[200010];
lol sum[200010],hash[200010][30];
inline void Hash() {
    for(lol i=1;i<=n;i++)
        for(lol j=1;j<=26;j++)
            hash[i][j]=(hash[i-1][j]*base%mod+(lol)(s[i]==('a'+j-1)))%mod;
}
inline void init() {
    sum[0]=1;
    for(lol i=1;i<=n;i++) sum[i]=sum[i-1]*base%mod;
}
bool check() {
    lol a[27],b[27];
    for(lol i=1;i<=26;i++) {
        a[i]=(hash[l+len-1][i]-sum[len]*hash[l-1][i]%mod+mod)%mod;
        b[i]=(hash[r+len-1][i]-sum[len]*hash[r-1][i]%mod+mod)%mod;
    }
    sort(a+1,a+27); sort(b+1,b+27);
    for(lol i=1;i<=26;i++) if(a[i]!=b[i]) return 0;
    return 1;
}
int main()
{
    in(n); in(m); scanf("%s",s+1);
    Hash(); init();
    while(m--) {
        in(l); in(r); in(len);
        if(check()) puts("YES");
        else puts("NO");
    }
    return 0;
}

博主蒟蒻,随意转载.但必须附上原文链接

http://www.cnblogs.com/real-l/

原文地址:https://www.cnblogs.com/real-l/p/9361301.html