1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營 第二場 A All with Pairs 字串hash KMP

2020牛客暑期多校訓練營 第二場 A All with Pairs 字串hash KMP

LINK:All with Pairs

那天下午打這個東西的時候狀態極差 推這個東西都推了1個多小時 (比賽是中午考試的我很困 沒睡覺直接開肝果然不爽

一開始看錯匹配的位置了 以為是\(1-l\)\(r-(r-l+1)\)進行匹配。

我想這不是隨便寫個trie樹???碼完發現過不去樣例 我真的是眼瞎

後來看清了。

大致思路如下 可以直接暴力列舉\(n^2\)個點對 找到最大的匹配位置這個也可以暴力 由於串長總和是M。

這一部分複雜度也不過是\(n^2+M\)的。

過不了 就可以思考能不能從大到小列舉匹配長度 看有多少對符合。

發現這樣也非常難做。

不過可以對單個串列舉匹配長度 然後看有多少個串可以進行匹配。

這樣容易想到字串hash 來進行快速的匹配 開C++11 直接unodered_map...

然後可以發現這樣做 會帶來重複 仔細觀察對於同一個串的重複位置 可以發現這是一個KMP的nex陣列的問題。

然後每次統計到一個位置就把自己的nex陣列的那個位置給減掉即可。

code
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 13331
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-4
#define sq sqrt
#define S second
#define F first
#define len(x) t[x].len
#define en(x) t[x].en
#define mod 998244353
#define M 1000000007
using namespace std;
const int MAXN=100010,maxn=1000010;
int n,cnt;
string a[MAXN];ll c[maxn];
map<ll,int>H[maxn];
ll p[maxn];
char b[maxn];
int nex[maxn];ll w[maxn];
inline void kmp(int n)
{
    int j=0;
    rep(2,n,i)
    {
        while(j&&b[j+1]!=b[i])j=nex[j];
        if(b[j+1]==b[i])++j;
        nex[i]=j;
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    ios::sync_with_stdio(false);
    cin>>n;int mx=0;
    rep(1,n,i)
    {
        cin>>a[i];
        mx=max(mx,(int)a[i].size());
        ll ha=0;
        vep(0,a[i].size(),j)
        {
            ha=(ha*P%M+(a[i][j]-'a'+1))%M;
            ++H[j+1][ha];
        }
    }
	p[0]=1;
    rep(1,mx,i)p[i]=(ll)p[i-1]*P%M;
    rep(1,n,i)
    {
        ll ha=0;
        reverse(a[i].begin(),a[i].end());
        int cnt=0;
        vep(0,a[i].size(),j)b[++cnt]=a[i][j],w[cnt]=0;
        kmp(cnt);cnt=0;
        vep(0,a[i].size(),j)
        {
            ++cnt;
            ha=(ha+(a[i][j]-'a'+1)*(ll)p[cnt-1])%M;
            if(H[cnt].find(ha)!=H[cnt].end())
            {
                ll cc=H[cnt][ha];
                c[cnt]+=cc;
                w[nex[cnt]]+=cc;
            }
        }
        rep(1,cnt,j)c[j]-=w[j];
    }
    ll ans=0;
    fep(mx,1,i)ans=(ans+(ll)i*i*c[i])%mod;
    cout<<ans<<endl;return 0;
}