白兔的字符串(哈希)

闲来无事学了下哈希,感觉上就是加密然后映射,下面直接上题目。
链接:https://ac.nowcoder.com/acm/problem/15253

题目描述

白兔有一个字符串T。白云有若干个字符串S1,S2…Sn。 白兔想知道,对于白云的每一个字符串,它有多少个子串是和T循环同构的。 提示:对于一个字符串a,每次把a的第一个字符移动到最后一个,如果操作若干次后能够得到字符串b,则a和b循环同构。 所有字符都是小写英文字母
输入描述:
第一行一个字符串T(|T|<=10^6)
第二行一个正整数n (n<=1000)
接下来n行为S1~Sn (|S1|+|S2|+…+|Sn|<=107),max(|S1|,|S2|,|S3|,|S4|,…|Sn|)<=106
输出描述:
输出n行表示每个串的答案

示例1

输入
abab
2
abababab
ababcbaba
输出
5
2

思路:将原先的字符串的所有循环同构的哈希值保存,然后每个查询就是直接查找是否存在该哈希值。我第一遍写的时候没注意会爆long long的情况,所以哈希值出现负的了,这里我们用unsigned long long就不会有这种情况了。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<queue>
#include<string>
#include<vector>
#include<map>
#include<set>
#define fi first
#define se second
#define pb push_back
#define me(a,b) memset(a,b,sizeof(a))
#define INIT() std::ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ll;//我只是懒得把下面的ll都改了,不要学我,还是用ull
typedef pair<int,int>P;
const int MAX_N=2000000+5;
const int INF=0x7fffffff;
const int inf=500000;
const double EPS=1e-6;
const ll base=123;
const ll mod=100007;
char s[MAX_N];
ll has[MAX_N];
ll h[MAX_N];
ll vis[MAX_N];
int viss[mod+5];
int pos=0;
struct node
{
   
    ll to;
    int next;
}rode[MAX_N];
void add(ll x)
{
   
    int xx=(int)(x%mod);
    rode[pos].to=x;
    rode[pos].next=viss[xx];
    viss[xx]=pos++;
}
int Find(ll x)
{
   
    int xx=(int)(x%mod);
    for(int i=viss[xx];i!=-1;i=rode[i].next)
    {
   
        if(rode[i].to==x)
            return 1;
    }
    return 0;

}
int main (void)
{
   
    memset(viss,-1,sizeof(viss));
    scanf("%s",s+1);
    int len=strlen(s+1);
    h[0]=(ll)1;
    int i;
    for(i=1;i<=2*len;i++)
    {
   
        h[i]=h[i-1]*base;
    }
    for(i=1;i<=len;i++)
    {
   
        s[len+i]=s[i];
    }
    for(i=1;i<=2*len;i++)
    {
   
        has[i]=base*has[i-1]+s[i]-'a';
        if(i>=len) add(has[i]-has[i-len]*h[len]);
    }

    int n;
    scanf("%d",&n);
    while(n--)
    {
   
        scanf("%s",s+1);
        int ans=0;
        has[0]=(ll)0;
        int l=strlen(s+1);
        for(i=1;i<=l;i++)
        {
   
            has[i]=has[i-1]*base+s[i]-'a';
            if(i>=len)
                ans+=Find(has[i]-has[i-len]*h[len]);
        }
        cout<<ans<<endl;
    }
}