zoukankan      html  css  js  c++  java
  • [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
    ",#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
    ",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
     
    */
    
  • 相关阅读:
    tornado与asyncmongo
    Grails/Groovy学习资源
    关于markdown
    Grails一些重要的配置文件
    Grails的目录结构
    Grails中的UrlMapping
    MVC已死,该是用MOVE的时候了
    算法——回溯法
    算法——分支限界法
    C#如何操控FTP
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13307387.html
Copyright © 2011-2022 走看看