[2020牛客暑期多校训练营(第二场)All with Pairs]

2020牛客暑期多校训练营(第二场)All with Pairs

题目大意:

给你一个n个字符串,分别是 \(s_1、s_2、s_3...s_n\) 定义 \(f(a,t)\) 等于最大的一个 \(i\) ,使得 \(a[1]a[2]...a[i]=t[|t|-i+1]...t[|t|]\)

求 : \(\sum_{i=1}^{n}{\sum_{j=1}^{n}{f(s_i,s_j)^2}} (mod\: 998244353)\)

题解:

这个也是看了题解补的。

  • 首先预处理一下所有的后缀,用hash存下来,然后枚举前缀,求出每一个长度相同前后缀的数量。

  • 但是这样写会出现重复计数的问题,比如有两个 \(aba\) ,那么对于这个会计算两个前缀,一个 \(a\) 一个 \(aba\) ,所以就会出现问题。

  • 所以接下来就要解决重复计数的问题,这个可以用 \(kmp\)\(next\) 数组来解决。字符串 \(p\)\(next[i]=j\) 表示的是 \(p_1p_2...p_{j-1}=p_{i-j+1}...p_i\)

  • \(cnt[i]\) 表示长度为 \(i\) 的相同前缀后缀的数量,所以去重就是从前往后 \(cnt[i-next[i]]-=cnt[i]\)

这个题目好像可以用AC自动机写,我先去学学,之后再补。

#include <bits/stdc++.h>
#define debug(x) printf("debug:%s=%d\n",#x,x);
//#define debug(x) cout << #x << ": " << x << endl;
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
const int MOD = 998244353;
const ll p = 27;
int nxt[maxn];
void getNext(string p){
    nxt[0] = -1;
    int i = 0, j = -1, len = p.size();
    while (i < len){
        if (j == -1 || p[i] == p[j]) {
            ++i,++j,nxt[i]=j;
        } 
        else j = nxt[j];
    }
}
typedef unsigned long long ull;
map<ull,ll>mp;
string s[maxn];
ll cnt[maxn];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>s[i];
        int len = s[i].size();
        ull sum=0,now=1;
        for(int j=len-1;j>=0;j--){
        	sum = ((s[i][j]-'a'+1)*now+sum);
            now=now*p;
            mp[sum]++;
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        int len = s[i].size();
        for(int j=0;j<=len+10;j++) cnt[j]=0,nxt[j]=0;
        s[i]+='*';
        getNext(s[i]);
        ull sum=0;
        for(int j=0;j<len;j++){
            sum = (sum*p+s[i][j]-'a'+1);
            cnt[j]+=mp[sum];
        }
        for(int j=0;j<len;j++){
            nxt[j]=nxt[j+1]-1;
            if(nxt[j]!=-1) cnt[nxt[j]]-=cnt[j];
        }
        for(int j=0;j<len;j++){
            ans=(ans+(j+1)*1ll*(j+1)*cnt[j])%MOD;
        }
    }
    printf("%lld\n",ans);
    return 0;
}
/*
4
bc
deedd
e
bdd
 
            bc      deedd       e       bdd
bc          2       0           0       0
deedd       0       5           0       1
e           0       0           1       0
bdd         0       0           0       3
 
2
aac
abdec
 
            aac         adbec
aac         3           0
abdec       0           5
 
 
4
abab
bcded
f
cffab
 
            abab        bcded       f       cffab
abab        4           0           0       2       20
bcded       1           5           0       1       20+27=47
f           0           0           1       0       47+1=48
cffab       0           0           0       5       48+25=73
 
*/
posted @ 2020-07-15 19:10  EchoZQN  阅读(134)  评论(0编辑  收藏  举报