zoukankan      html  css  js  c++  java
  • [NOI 2016] 优秀的拆分

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=4650

    [算法]

            首先 , 求形如"AABB"的子串个数 , 我们只要预处理 :

            Fi : 以i为最后一个字符的所有子串中 , 有多少个“AA"串

            Gi :以i为第一个字符的所有子串中 , 有多少个"BB"串

            那么 , 第i个位置对答案的贡献即为Fi * Gi+1 , 贡献相加为答案

            用字符串哈希暴力预处理F和G , 可以拿到95分

            那么 , 怎样拿到100分呢?

            不难发现 , 其实我们只要能求出形如"AA"的子串 , 问题就解决了

            不妨枚举长度L , 为”AA"长度的一半 , 每个下标为L倍数的位置我们称之为“关键点” 

            每次枚举相邻两个关键点i , j , 求出 :

            lcp = LCP(pre(i) , pre(j)) 

            lcs = LCS(Suf(i - 1) , suf(j - 1))

            若lcp + lcs >= L , 那么就对中间的一段区间产生了“贡献” , 可以画图理解

            可以差分前缀和 + 字符串哈希解决

            时间复杂度 : O(NlogN ^ 2) (调和级数 : n / 1 + n / 2 + .. + n / n = nlogn)

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 30010;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int P = 3e7 + 7;
    
    int n;
    ll pref[N] , suf[N];
    int H[N] , pw[N];
    char s[N];
    
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline int gethash(int l , int r)
    {
        int ret = (H[r] - 1ll * H[l - 1] * pw[r - l + 1] % P) % P;
        if (ret < 0) ret += P;
        ret %= P;
        return ret;
    }
    
    int main()
    {
        
        int T;
        read(T);
        while (T--) 
        {
            scanf("%s" , s + 1);
            n = strlen(s + 1);
            memset(pref , 0 , sizeof(pref));
            memset(suf , 0 , sizeof(suf));
            memset(H , 0 , sizeof(H));
            memset(pw , 0 , sizeof(pw));
            pw[0] = 1;
            for (int i = 1; i <= n; i++) pw[i] = 1ll * pw[i - 1] * 131 % P;
            for (int i = 1; i <= n; i++) H[i] = (1ll * H[i - 1] * 131 + s[i] - 'a' + 1) % P;
            for (int L = 1; L <= n; L++)
            {
                    for (int i = L; i + L <= n; i += L)
                    {
                            int j = i + L;
                            int l = 1 , r = L - 1 , lcs = 0 , lcp = 0;
                            while (l <= r)
                            {
                                    int mid = (l + r) >> 1;
                                    if (gethash(j - mid , j - 1) == gethash(i - mid , i - 1))
                                    {
                                            lcs = mid;
                                            l = mid + 1;
                                    } else r = mid - 1;
                            }
                            l = 1 , r = L;
                            while (l <= r)
                            {
                                    int mid = (l + r) >> 1;
                                    if (gethash(i , i + mid - 1) == gethash(j , j +  mid - 1))
                                    {
                                            lcp = mid;
                                            l = mid + 1;
                                    } else r = mid - 1;
                            }
                            if (lcp + lcs < L) continue;
                            int t = lcp + lcs - L + 1; 
                            ++pref[j + lcp - t]; --pref[j + lcp];
                            ++suf[i - lcs]; --suf[i - lcs + t];
                    }
            }
            ll ans = 0;
            for (int i = 1; i <= n; i++) pref[i] += pref[i - 1];
            for (int i = 1; i <= n; i++) suf[i] += suf[i - 1];
            for (int i = 1; i < n; i++) ans += 1ll * pref[i] * suf[i + 1];
            printf("%lld
    " , ans);
        } 
        
        return 0;
    }
  • 相关阅读:
    第12课 计算器核心解析算法(上)
    第11课 Qt中的字符串类
    第10课 初探 Qt 中的消息处理
    第9课 计算器界面代码重构
    第8课 启航!第一个应用实例
    第7课 Qt中的坐标系统
    第6课 窗口部件及窗口类型
    第5课 Qt Creator工程介绍
    第4课 Hello QT
    给Linux内核增加一个系统调用的方法(转)
  • 原文地址:https://www.cnblogs.com/evenbao/p/10427098.html
Copyright © 2011-2022 走看看