Isomorphic Strings(哈希)--2020杭电多校

Isomorphic Strings

题目传送门

Isomorphic Strings

题目大意

给一个字符串 s ,长度为 n ,问是否存在一个 k ,满足 k∣n ,将 s 分成相等的 k 段子串,每一段子串互为循环同构。

思路

Isomorphic Strings(哈希)--2020杭电多校_第1张图片
主要是求得第一个子串的所有循环同构的哈希值集合,若第一个集合为第二个的子集,就合法

AC Code

#include 
using namespace std;
typedef long long ll;
const int mod=1e7 +7;
const int N=5e6+6;
const int maxn=2e7;
const int base=1543;
int T, n;
char s[N];
int Hash[N],por[N];
int id[maxn],cnt;
void init(){                        //初始化por数组
    por[0]=1;
    for(int i=1;i<N;i++)    por[i]=1LL*por[i-1]*base%mod;
}
void get_hash(int len, char s[]){   //哈希处理总的长度的字符串
    for(int i=1;i<=len;i++) 
        Hash[i]=(1LL*Hash[i-1]*base%mod+(s[i]-'a'+1))%mod;
}
int js(int l, int r){     //子串的哈希值
    return (Hash[r]-1LL*Hash[l-1]*por[r-l+1]%mod+mod)%mod;
}
bool solve(int d,int cnt)
{
    if(d==1)    return 0;
    int len=n/d;
    int l=1, r=len;
    int tmp=js(l,r);
    id[tmp]=cnt;
    for(int i=1;i<len;i++){   //同构的其它串的hash值
        tmp=(1LL*js(i+1,len)*por[i]%mod +js(1,i))%mod;
        id[tmp]=cnt;
    }
    for(int i=1;i<=d;i++){  //判断后面的子串是否合法
        int x=js(l,r);
        if(id[x]!=cnt) return 0;
        l+=len, r+=len;
    }
    return 1;
}
int main()
{
    init();
    scanf("%d",&T);
    cnt=0;
    while(T--)
    {
        scanf("%d",&n);
        scanf("%s",s+1);
        get_hash(n, s);
        int flag=0;
        for(int i=1;i*i<=n && !flag;i++)//枚举段数
        {
            if(n%i==0){
                flag|=solve(i,++cnt);
                flag|=solve(n/i,++cnt);
            }
        }
        if(flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

你可能感兴趣的:(2020杭电多校,哈希,哈希,2020杭电多校)