题:https://ac.nowcoder.com/acm/contest/5667/A
题意:给定n个串,主要求每个串和n个中的每一个串的最大相同公共前后缀的长度,然后计算题目给式子
分析:对于n个串的后缀,我们考虑用哈希值来代表,最多共有1e6个值(sum(|si|)),预处理这部分,用map记录哈希值出现的个数;
然后简单点考虑就枚举前缀,直接算当前前置的哈希值在之前预处理的后缀中出现了多少次;
但会造成“重复”的现象,比如枚举的前缀的前缀在后缀中还有贡献,这无疑是会重复算的,而我们只要最大,这些“前缀的前缀”不能算进答案里面;
所以我们考虑可以用kmp的next数组,next数组的含义即 i 位匹配错了要跳转去哪个位置,所以大前缀的贡献为num[i], 则相应的大前缀的前缀要减去这部分贡献,即num[next[i]]-num[i];
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair typedef long long ll; typedef unsigned long long ull; const int mod=998244353; const int M=1e6+6; const int N=1e5+5; const int inf=0x3f3f3f3f; const ll INF=1e18; const ull base=217; unordered_map<ull,int>mp; vector<ull>a[N]; vector<int>nex[N]; ull jinzhi[M]; ll num[M]; char s[M]; void getnext(int id){ int m=strlen(s+1); int j=0; nex[id].resize(m+1); for(int i=2;i<=m;i++){ while(j&&s[i]!=s[j+1]) j=nex[id][j]; if(s[i]==s[j+1]) j++; nex[id][i]=j; } } int main(){ jinzhi[0]=1; for(int i=1;i<M;i++) jinzhi[i]=jinzhi[i-1]*base; int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",s+1); int len=strlen(s+1); a[i].resize(len+1); a[i][0]=0; for(int j=1;j<=len;j++) a[i][j]=a[i][j-1]*base+(s[j]-'a'+1); for(int j=0;j<len;j++){ ull tmp=a[i][len]-a[i][j]*jinzhi[len-j]; mp[tmp]++; } getnext(i); } ll ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<nex[i].size();j++){ num[j]=mp[a[i][j]]; num[nex[i][j]]-=num[j]; } for(int j=1;j<nex[i].size();j++){ ans=(1ll*num[j]*j%mod*j%mod+ans)%mod; } ///cout<<ans<<endl; } printf("%lld ",ans); return 0; }