• [Codeforces 17E] Palisection


    Brief Intro:

    求所有相交的回文子串的个数。

    Algorithm:

    求回文子串,肯定要先Manacher

    我们可以发现判断相交要考虑多种情况,既有相交又有包含,难以成段计算

    但两子串不相交的条件只有一个,即A子串的右边界严格小于B子串的左边界,再用总个数相减即可

    我们用差分维护l[i],r[i]分别表示左/右边界恰好为i的个数,同时维护r[i]的前缀和,即可O(n)地更新答案

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    
    const int MAXN=2e6+10;
    const int MOD=51123987;
    int len,m[2*MAXN],l[2*MAXN],r[2*MAXN],mx,mid;
    string dat,s;
    
    void init()
    {
        s="!#";
        for(int i=0;i<dat.size();i++)
            s.append(dat,i,1),s.append("#");
        s.append("@");
    }
    
    int main()
    {
        cin >> len >> dat;
        init();
        
        mx=0;mid=0;
        for(int i=1;i<s.size()-1;i++)
        {
            if(i<mx) m[i]=min(mx-i,m[2*mid-i]);
            else m[i]=1;
            
            while(s[i+m[i]]==s[i-m[i]]) m[i]++;
            
            if(i+m[i]>mx) mx=i+m[i],mid=i;
        }
        
        ll res=0,sum=0;
        for(int i=1;i<s.size()-1;i++)
        {
            l[i-m[i]+1]++;l[i+1]--;r[i]++;r[i+m[i]]--; //求出该点最长回文串后,这一段均为回文子串,都要将l[i]和r[i]更新
            (res+=m[i]/2)%=MOD;
        }
        
        res=res*(res-1ll)/2%MOD;
        
        for(int i=1;i<s.size()-1;i++)
        {
            l[i]+=l[i-1];r[i]+=r[i-1];
            if(i%2==0) (res-=sum*l[i]%MOD)%=MOD,(sum+=r[i])%=MOD; 
        }
        cout << (res+MOD)%MOD; //取模出现减法要先加模数防止出现负数
        
        return 0;
    }

    Review:

    1、当正向求解情况太多时,考虑反向求解,再用总个数相减

          ex:求解区间相交性问题时即可算出不相交的个数

    2、当数据更新时为区段增减,考虑使用差分法维护,在O(n)内实现

    3、求解区间相交问题,维护每个点恰为左右边界的个数和右边界的前缀和即可O(n)求解

  • 相关阅读:
    洛谷1509 找啊找啊找GF
    要怎样努力,才能成为很厉害的人?
    随笔
    2018NOIP模拟题 曲线
    洛谷4147 玉蟾宫
    洛谷2258 子矩阵
    Vijos 纸牌
    [leetcode] Word Break
    [leetcode] Maximum Binary Tree
    [leetcode] Binary Tree Preorder Traversal
  • 原文地址:https://www.cnblogs.com/newera/p/9034331.html
Copyright © 2020-2023  润新知