• Mediocre String Problem (manacher+扩展kmp+差分)


    题目大意:

    给出,s1,s2, 挑一些 s1的字串+s2的前缀字串,看他们是不是回文串, len(subs1)>len(subs2)>1=1;

    统计有多少个

    • 首先 subs1是要和s2成回文,他的内部也要是回文,于是就分为2部分
    • 求第一部分: 把s1翻转,然后来求一个扩展kmp,对于目标窜s2,求的是个数,那么求出的最大长度就有len个那个ans
    • 然后看后面部分是不是回文窜,如何看有多少个? 就是看有一个回文串是以后面那个字母位开始(因为翻转了,就是前面一个字母,最后在翻回去)
    • 利用manacher来求出这个东东
    • 利用差分来来搞,因为求出的是最大的回文串,字串也要计入贡献
    • 最后统计一下就ok了
    • 详细情况看代码
    #include <bits/stdc++.h>
    using namespace std;
    #define ri register int
    #define M 4000015
    
    int n,m;
    string s1,s2;
    int nxt[M];
    int et[M];
    void getnxt()
    {
        int len=s2.length();
        nxt[0]=len;
        int i=0;
        while(s2[i]==s2[i+1]&&i+1<len) i++;nxt[1]=i;
        int po=1;
        for(ri i=2;i<len;i++)
        {
            if(nxt[i-po]+i<po+nxt[po])
            {
                nxt[i]=nxt[i-po];
            }
            else
            {
                int j=po+nxt[po]-i;
                if(j<0) j=0;
                while(j<len&&s2[j]==s2[i+j]) j++;nxt[i]=j;
                po=i;
            }
        }    
        
    }
    long long num[M];
    long long nn[M];
    string s;
    void getet()
    {
        for(ri i=s1.length()-1,j=0;i>=0;i--,j++)
        {
           s[j]=s1[i];
        }
        int i=0;
        int l1=s1.length(),l2=s2.length();
        while(s[i]==s2[i]&&i<l2&&i<l1) i++;
        et[0]=i;
        int po=0;
        for(ri i=1;i<l1;i++)
        {
            if(nxt[i-po]+i<po+et[po])
            {
                et[i]=nxt[i-po];
            }
            else
            {
                int j=po+et[po]-i;
                if(j<0) j=0;
                while(j<l2&&i+j<l1&&s[i+j]==s2[j]) j++;et[i]=j;
                po=i;
            }
            num[i-1]=et[i];
        //    cout<<num[i-1]<<" ";
        }
        for(ri i=s1.length()-1,j=0;i>=0;i--,j++)
        {
           nn[j]=num[i];
        }
        
    }
    long long ans=0;
    int p[M];
    void manacher()
    {
        s="$#";
        for(ri i=0;i<s1.length();i++)
        {
            s+=s1[i];
            s+="#";
        }
        int mid=0,r=0;
        for(ri i=0;i<s1.length();i++) num[i]=0;
        for(ri i=0;i<s.length();i++)
        {
            if(i<r)
            {
                p[i]=min(r-i+1,p[2*mid-i]);
            }
                while(s[i-p[i]]==s[i+p[i]]) p[i]++;
               if(p[i]+i>r) r=p[i]+i-1,mid=i;
               int b=(i-p[i])/2;
               if((p[i]-1)&1)
               {
                     int a=(i-p[i])/2;
                     
                    num[a]+=1;
                    num[a+((p[i]-1)/2)+1]+=-1;
               }
               else
               {
                     int a=(i-p[i])/2;
                    num[a]+=1;
                    num[(p[i]-1)/2+a]+=-1;
               }
            
        }
        
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        
        cin>>s1>>s2;
        getnxt();
        getet();
        manacher();
        long long arr=0;
        for(ri i=0;i<s1.length();i++)
        {
           arr+=num[i];
           ans+=arr*nn[i];
        }
        cout<<ans;
        
    }
    View Code

    后记:

    • 为了方便,内存开4倍
    • 注意在处理回文的时候,找他的真实位置(初始位置来确定,而不是 i
    • p[i]-1 是0,可以直接跳过
    • 思路就是,想思路,然后遇到新的问题,在此基础上想解决方案,而不是重新开始
  • 相关阅读:
    mongodb 3.4复制搭建
    mongodb 用户管理
    mongodb 3.4 TAR包启动多个实例
    mongodb 3.4 YUM安装
    mongodb数据库备份恢复-windows系统
    mongodb数据库索引管理
    mongodb数据库集合操作
    Unity3d 实现鼠标左键点击地形使角色移动到指定地点[脚本]
    Unity3D性能优化之Draw Call Batching
    Unity3D占用内存太大怎么解决呢?
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/16474469.html
Copyright © 2020-2023  润新知