码迷,mamicode.com
首页 > 其他好文 > 详细

Wannafly挑战赛11 D 白兔的字符串 Hash

时间:2018-03-13 01:02:09      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:har   http   void   子串   ++   覆盖   输入   正整数   sig   

Wannafly挑战赛11

D   白兔的字符串

白兔有一个字符串T。白云有若干个字符串S1,S2..Sn

白兔想知道,对于白云的每一个字符串,它有多少个子串是和T循环同构的。

提示:对于一个字符串a,每次把a的第一个字符移动到最后一个,如果操作若干次后能够得到字符串b,则a和b循环同构。

所有字符都是小写英文字母

输入描述:

第一行一个字符串T(|T|<=10^6)
第二行一个正整数n (n<=1000)
接下来n行为S1~Sn (|S1|+|S2|+…+|Sn|<=10^7),max(|S1|,|S2|,|S3|,|S4|,..|Sn|)<=10^6

输出描述:

输出n行表示每个串的答案
示例1

输入

abab
2
abababab
ababcbaba

输出

5
2

tags:字符串 Hash

把 T 在 Hash 后存在 set 里,再对每个 S 找子串。但要用 unordered_set ,否则会超时。

技术分享图片
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
typedef  unsigned long long  ull;
const int N = 1000005, Base=1e9+7;

unordered_set< ull > Set;
ull  p[N];
void Init(char* T)
{
    int len = strlen(T);
    ull  Hash = 0;
    p[0] = 1;
    rep(i,0,len-1) {
        Hash = Hash*Base+T[i];
        p[i+1] = p[i]*Base;
    }
    rep(i,0,len-1) {
        Hash = (Hash-T[i]*p[len-1])*Base + T[i];
        Set.insert(Hash);
    }
}
int solve(char* S, int lenT)
{
    int lenS = strlen(S);
    if(lenS < lenT) return 0;
    ull  Hash = 0;
    int ret = 0;
    rep(i,0,lenT-1) Hash = Hash*Base+S[i];
    if(Set.count(Hash)) ++ret;
    rep(i,lenT,lenS-1) {
        Hash = (Hash-S[i-lenT]*p[lenT-1])*Base + S[i];
        if(Set.count(Hash)) ++ret;
    }
    return ret;
}
char T[N], S[N];
int main()
{
    scanf("%s", T);
    Init(T);
    int lenT = strlen(T);
    int n;  scanf("%d", &n);
    while(n--)
    {
        scanf("%s", S);
        printf("%d\n", solve(S, lenT));
    }

    return 0;
}
View Code

 

正解是:

标算是ex_kmp。用R[i]表示S[i..len]和T的最长公共前缀,L[i]表示S[1..i]和T的最长公共后缀,当L[i]+R[i+1]>=|T|时,可以给一段区间打上标记。如果T的一个表示法在某个位置出现则至少会被一个标记覆盖。然后就变成了区间加法,求有多少个正数。用差分+前缀和即可。

Wannafly挑战赛11 D 白兔的字符串 Hash

标签:har   http   void   子串   ++   覆盖   输入   正整数   sig   

原文地址:https://www.cnblogs.com/sbfhy/p/8552524.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!