• 「manacher」


    前言

    发现大神指$skyh$都用$manacher$水回文自动机的题,就学了学这个做法。

    应用

    • 求以某个点为中心的最长回文半径
    • $O(n)$
    • 由第一点可以拓展求以某个点为终点/起点的最长回文
    • 没了(怎么感觉跟回文自动机差不多的说)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e7;
    int n,r[N];
    char str[N],s[N];
    int main(){
        scanf("%s",str+1);int l=strlen(str+1);
        s[0]='/'; s[++n]='%';
        for(int i=1;i<=l;++i) s[++n]=str[i],s[++n]='%';
        int ans=-0x3f3f3f3f;
        for(int i=1,maxr=0,thatmid=0;i<=n;++i){
            int j=2*thatmid-i;
            if(i<=maxr) r[i]=min(r[j],maxr-i+1);
            while(s[i+r[i]]==s[i-r[i]]) ++r[i];
            if(r[i]+i-1>maxr) maxr=i+r[i]-1,thatmid=i;
            ans=max(ans,r[i]);
        }
        printf("%d
    ",ans-1);
    }

    例题

    P1659 [国家集训队]拉拉队排练

    求前k长回文。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=2e6+50,mod=19930726;
    ll n,k,r[N],len[N];
    char s[N],str[N];
    ll mgml(ll a,ll b,ll ans=1){
        for(;b;b>>=1,a=a*a%mod) if(b&1) ans=ans*a%mod;
        return ans;
    }
    int main(){
        scanf("%lld%lld%s",&n,&k,str+1); int l=strlen(str+1);
        s[n=0]='/';s[++n]='%';
        for(int i=1;i<=l;++i) s[++n]=str[i],s[++n]='%';
        for(ll i=1,maxr=0,thatmid=0;i<=n;++i){
            int j=thatmid*2-i;
            if(i<=maxr) r[i]=min(maxr-i+1,r[j]);
            while(s[i+r[i]]==s[i-r[i]]) ++r[i];
            if(i+r[i]-1>=maxr) maxr=i+r[i]-1,thatmid=i;
            if(i&1ll^1ll) len[r[i]-1]++;
        }
        int st=(n&1ll)?n:n-1;
        ll ans=1;
        for(int i=st;i>=1;i-=2){
            len[i]+=len[i+2];
            ll Lim=min(len[i],k);
            ans=ans*mgml(i,Lim)%mod;
            k-=Lim;
            if(!k) break;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    P4555 [国家集训队]最长双回文串

    求以某个点为起点/终点的最长回文。

    还是上模板,然后因为要保证两个回文拼接起来不能交叉,于是就枚举'%'作为分界点统计答案。

    再计算以某个点为起点/终点的最长回文有个方法,在$manacher$中只把饱和回文加进数组,最后再$O(n)$扫数组向一边更新答案,因为要两个回文拼接起来,因此一个回文的不算。

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=4e5+50;
    int n,r[N],L[N],R[N];
    char s[N],str[N];
    signed main(){
        scanf("%s",str+1); int l=strlen(str+1);
        s[n=0]='/';s[++n]='%';
        for(int i=1;i<=l;++i) s[++n]=str[i],s[++n]='%';
        for(int i=1,maxr=0,thatmid=0;i<=n;++i){
            int j=thatmid*2-i;
            if(i<=maxr) r[i]=min(maxr-i+1,r[j]);
            while(s[i+r[i]]==s[i-r[i]]) ++r[i];
            if(i+r[i]-1>=maxr) maxr=i+r[i]-1,thatmid=i;
            L[i-r[i]+1]=max(L[i-r[i]+1],r[i]-1);
            R[i+r[i]-1]=max(R[i+r[i]-1],r[i]-1);
    //        printf("%d %d %d %d %d
    ",i-r[i]+1,L[i-r[i]+1],i+r[i]-1,R[i+r[i]-1],r[i]-1);
        }
        for(int i=1;i<=n;i+=2) L[i]=max(L[i],L[i-2]-2);
        for(int i=n;i>=1;i-=2) R[i]=max(R[i],R[i+2]-2);
        long long ans=0;
        for(int i=1;i<=n;i+=2) if(L[i]&&R[i]) ans=max(ans,(long long)L[i]+R[i]);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    [原创]什么是安全性测试
    [原创]如何有效的考核测试人员
    [原创]MySql官方压力测试工具Mysqlslap
    [原创软件测试工作技能
    [原创]如何有效构建测试环境
    [原创]常见系统测试类型总结
    [原创]Kjava手机顽童模拟器
    [原创]浅谈测试人员提交缺陷记录
    [原创]Windows/Unix 资源性能计数器
    [原创]戴明PDCA方法
  • 原文地址:https://www.cnblogs.com/hzoi2018-xuefeng/p/12103744.html
Copyright © 2020-2023  润新知