zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第二场)All with Pairs

    题目链接

    https://ac.nowcoder.com/acm/contest/5667/A

    题目大意

    定义 f(s , t) 为 s 的前缀和 t 的后缀的最大匹配,求$sum ^{n}_{i=1}sum ^{n}_{j=1}fleft( s_{i},s_{j} ight) ^{2}$

    解题思路

    一个很显然的做法:

    先对字符串进行 hash , 然后用 cnt 统计每个字符串的所有后缀的个数 , 再遍历每个字符串的所有前缀统计个数即可

    然而我们会发现上述做法会有重复统计的情况 , 如 f ("abab" , "aba")

    "abab" 和 "aba" 最大匹配前后缀很显然是 "aba",但如若我们用上述方法直接统计就会算上 cnt["a"]

    而 "a" 为 "aba" 和 "aba" 的最大前后缀匹配(不包含本身) , 也就是 "aba" 在失配情况下得到的次大匹配

    这不正是 kmp 的 next 数组吗 ? 

    于是我们只要在每次统计前缀 S 时减去这个前缀对应 next 数组的值即可(ans += cnt[S] - cnt[nex[ S ]])

    AC_Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define ull unsigned long long
    const int base = 233;
    const int N = 1e6 + 10 , mod = 998244353;
    ull power[N] , suf[N];
    string s[N];
    unordered_map<ull , int>cnt;
    int n , ans , nex[N] , now[N];
    void get_nex(string s , int *nex)
    {
        int i = 0 , j = -1 , len = s.size();
        nex[i] = j;
        while(i < len)
        {
            while(j != -1 && s[i] != s[j]) j = nex[j];
            nex[++ i] = ++ j ;
        }
    }
    void Hash(string s)
    {
        ull suf = 0 , p = 1;
        for(int i = s.size() - 1 ; i >= 0 ; i --)
        {
            suf += p * (s[i] - 'a' + 1);
            p *= base;
            cnt[suf] ++ ;
        }
    }
    long long get(int x)
    {
        return x * x % mod;
    }
    signed main()
    {
        ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
        cin >> n; 
        for(int i = 1 ; i <= n ; i ++)
        {
            cin >> s[i];
            Hash(s[i]);
        }
        for(int i = 1 ; i <= n ; i ++)
        {
            ull pre = 0 , p = 233;
            int len = s[i].size();
            get_nex(s[i] , nex);
            for(int j = 0 ; j < len ; j ++)
            {
                pre = pre * p + (s[i][j] - 'a' + 1) ;        
                now[j] = cnt[pre];
            }
            for(int j = 0 ; j < len ; j ++) now[nex[j + 1] - 1] -= now[j];
            for(int j = 0 ; j < len ; j ++) ans += now[j] * get(j + 1) , ans %= mod;
        }
        cout << ans << '
    ';
        return 0;
    }
  • 相关阅读:
    redis运维的一些知识点
    nginx 实现Web应用程序的负载均衡
    JQuery中常用方法备忘
    高效程序猿之 VS2010快速生成代码模板
    C# var 隐式类型 var 用法 特点
    HTML之打开/另存为/打印/刷新/查看原文件等按钮的代码
    js函数大全(2)
    js常用函数大全107个
    js键盘键值大全
    js键盘键值大全
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/13343247.html
Copyright © 2011-2022 走看看