牛客国庆集训派对Day5 H-我不爱她 (KMP+字符串哈希)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/82959079

链接:https://www.nowcoder.com/acm/contest/205/H
来源:牛客网
 

题目描述

终于活成了自己讨厌的样子。
 

天空仍灿烂,它爱着大海。

你喜欢大海,我爱过你。

世界上充满了巧合。我们把每句话当成一个字符串,我们定义a对b的巧合值为a的最长后缀的长度并且它是恰好是b的前缀,这里的后缀或者前缀包括字符串的本身。
比如字符串“天空仍灿烂她喜欢大海”对“她喜欢大海我不爱她了我爱的只是与她初见时蔚蓝的天空”的巧合值为5,而字符串“她喜欢大海我不爱她了我爱的只是与她初见时蔚蓝的天空”对“天空仍灿烂她喜欢大海”的巧合值为2。
现在给出n个字符串由"ab"构成的字符串s1,s2,...,sn,求出对于所有1≤ i,j≤ n,si对sj的巧合值的和。

输入描述:

第一行一个整数T(T≤ 1000),表示数据组数。
每组数据第一行一个正整数n(1≤ n≤ 105)。接下来n行每行一个字符串si,保证字符串由"ab"构成。
保证单组数据有,保证所有数据有。

输出描述:

对于每组数据,输出一个整数,表示答案。

示例1

输入

复制

1
2
abb
bab

输出

复制

9

解题思路:很容易想到哈希,对每一个字符串的所有前缀哈希,用一个map记录哈希值出现的(次数*字符串长度)

然后再枚举所有字符串的后缀,求哈希值,然后更新答案 ans+=mp[hash];

这么想貌似可做,但是可能会出现重复计算的情况如单个字符串

ababab

我们在枚举后缀的时候,会把 ab,abab也算进了答案里面,但是题目只用求最长的。因此我们要计算出每个前缀对答案新增的贡献是多少。考虑,ab,abab,ababab,ab对答案新增了2,abab对答案也新增了2,ababab对答案也贡献了2.加起来就是6,那么这个贡献怎么算呢?不难看出,就是字符串长度减去该字符串的后缀的最长公共前缀。就是len-next[len]。

#include <iostream>
#include <vector>
#include <string.h>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 1500005;
unordered_map<ull,ll> mp;
ull P1 = 131;
ull g[MAXN];
ull Hash[MAXN];
ull getHash(int x, int len)
{
    return Hash[x + len - 1] - Hash[x - 1] * g[len];
}
void hhash(char *s, int len)
{
    for (int i = 1; i <= len; i++)
        Hash[i] = (Hash[i - 1] * P1 + s[i - 1]);
}

void kmp(char *s,int len,int *nxt){
    int i,j;
    j=nxt[0]=-1;
    i=0;
    while(i<len){
        while(j!=-1&&s[i]!=s[j])
            j=nxt[j];
        nxt[++i]=++j;
    }
}

char s[MAXN];
int nxt[MAXN];
int len[MAXN];
int slen[MAXN];
ll ans=0;
int main()
{
    g[0] = 1;
    for (int i = 1; i <= MAXN - 1; i++)
        g[i] = (g[i - 1]) * P1;
    int T;
    scanf("%d", &T);
    while (T--)
    {
        mp.clear();
        ans=0;
        int N;
        scanf("%d",&N);
        for(int i=0;i<N;i++){
            scanf("%s",s+slen[i]);
            len[i]=strlen(s+slen[i]);
            slen[i+1]=slen[i]+len[i];
        }

        hhash(s,slen[N]);

        for(int i=0;i<N;i++){
            kmp(s+slen[i],len[i],nxt);
            for(int j=1;j<=len[i];j++)
                mp[getHash(1+slen[i],j)]+=j-nxt[j];
        }

        for(int i=0;i<N;i++)
            for(int j=1;j<=len[i];j++)
                ans+=mp[getHash(1+slen[i]+j-1,len[i]-j+1)];
        printf("%lld\n",ans);

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/82959079
今日推荐