zoukankan      html  css  js  c++  java
  • Manacher

    果然还是要把manacher的一些经典题打一下。


     拉拉队排练

    求前K长的回文串(长度为奇数)的长度乘积。

    如果有长度为7的回文串,就一定有长度1 3 5 的回文串。

    一遍manacher把有的长度打上差分标记,最后快速幂计算即可。

    #include<bits/stdc++.h>
    #define N 1000003
    #define LL long long
    #define mod 19930726
    using namespace std;
    int n,len,last;
    LL K; 
    int pal[N<<1];
    LL cha[N];
    char s[N<<1],t[N];
    void init()
    {
        len=strlen(t);
        s[0]='-';
        for(int i=1;i<2*len;i+=2)
        {
            s[i]='#';
            s[i+1]=t[i/2];
        }
        s[2*len+1]='#';
        s[2*len+2]='+';
        s[2*len+3]='';
        last=len;
        len=2*len+1;
    }
    void manacher()
    {
        int id,mx=0;
        for(int i=1;i<=len;++i)
        {
            if(mx>=i)pal[i]=min(pal[2*id-i],mx-i+1);
            else pal[i]=1;
            while(s[i-pal[i]]==s[i+pal[i]])pal[i]++;
            if(i+pal[i]-1>mx)mx=i+pal[i]-1,id=i;
            if(s[i]!='#')cha[1]++,cha[pal[i]]--;
        }
    }
    LL quick(LL a,LL x)
    {
        LL ans=1;
        while(x)
        {
            if(x&1)ans=ans*a%mod;
            a=a*a%mod;x>>=1;
        }
        return ans;
    }
    int main()
    {
        scanf("%d%lld
    ",&n,&K);
        scanf("%s",t);
        init();
        manacher();
        for(int i=1;i<=last;i++)
          cha[i]+=cha[i-1];
        int j=last;
        LL num=0;
        if(j%2==0)j--;
        LL ans=1;
        while(num<K&&j>0)
        {
            while(cha[j]<=0&&j>0)j-=2;
            if(j<=0)break;
            LL p=min(cha[j],K-num);
            num+=p;
            ans=ans*quick(j,p)%mod;
            j-=2;
        }
        if(num<K)printf("-1
    ");
        else printf("%lld
    ",ans);
    } 
    /*
    3 3
    aabbccbbaa
    
    3 5
    abc
    */
    拉拉队排练

    最长双回文串

    先处理出每个点最左和最优能被哪个回文中心覆盖到。

    以向左为例:对于每个回文中心i,把mx到i+pal[i]-1打上i的标记。

    向右同理。

    枚举左回文串与右回文串的断点“#”,取长度相加的max。

    #include<bits/stdc++.h>
    #define N 100003
    #define LL long long
    #define mod 19930726
    using namespace std;
    int n,len,last;
    LL K; 
    int pal[N<<1],tl[N<<1],tr[N<<1];
    LL cha[N];
    char s[N<<1],t[N];
    void init()
    {
        len=strlen(t);
        s[0]='-';
        for(int i=1;i<len*2;i+=2)
        {
            s[i]='#';
            s[i+1]=t[i/2];
        }
        s[len*2+1]='#';
        s[len*2+2]='+';
        s[len*2+3]='';
        len=len*2+1;
    //    for(int i=1;i<=len;++i)printf("%c",s[i]);    printf("
    ");
    }
    void manacher()
    {
        int id,mx=0;
        for(int i=1;i<=len;++i)
        {
            if(mx>=i)pal[i]=min(pal[2*id-i],mx-i+1);
            else pal[i]=1;
            while(s[i-pal[i]]==s[i+pal[i]])pal[i]++;
            if(i+pal[i]-1>mx)mx=i+pal[i]-1,id=i;
        }
    }
    int main()
    {
        scanf("%s",t);
        int n=strlen(t);
        init(); 
        manacher();
        int ml=1;
        for(int i=1;i<=len;++i)
          for(;ml<=i+pal[i]-1;++ml)
            tl[ml]=i;//存的回文中心的位置 
        int mr=len;
        for(int i=len;i>=1;--i)
          for(;mr>=i-pal[i]+1;--mr)
            tr[mr]=i;
        int ans=2;
        for(int i=1;i<n;i++)//枚举# 
          ans=max(ans,tr[2*i+1]-tl[2*i+1]);
          //别忘了中间还有#号,tl和tr的位置相当于就是已经乘了2,所以算出来是双回文串的真实长度而不是一般 
        printf("%d
    ",ans);
    } 
    /*
    baacaabbacabb
    aaaaaaaaaa
    */
    最长双回文串

    CF13E palisection

    求相交回文串对数。

    正难则反。我们求不相交对数。

    设L[i]为以i为开头的回文串个数。R[i]为以i为结尾的回文串个数。

    有以i-pal[i]+1 ~ i-1开头的回文串个数,R同理。

    打差分标记即可。

    每次用总数减去不相交的即可。

    #include<bits/stdc++.h>
    #define N 2000003
    #define LL long long
    #define mod 51123987
    using namespace std;
    int len,last; 
    int pal[N<<1],l[N<<1],r[N<<1];
    char s[N<<1],t[N];
    LL quick(LL a,LL x)
    {
        LL res=1;
        while(x)
        {
            if(x&1)res=res*a%mod;
            a=a*a%mod;x>>=1;
        }
        return res;
    }
    void init()
    {
        s[0]='-';
        for(int i=1;i<2*len;i+=2)
        {
            s[i]='#';
            s[i+1]=t[i/2];
        }
        s[2*len+1]='#';
        s[2*len+2]='+';
        s[2*len+3]='';
        len=2*len+1;
    }
    LL ans=0;
    void manacher()
    {
        int id,mx=0;
        for(int i=1;i<=len;++i)
        {
            if(mx>=i)pal[i]=min(pal[2*id-i],mx-i+1);
            else pal[i]=1;
            while(s[i+pal[i]]==s[i-pal[i]])pal[i]++;
            if(i+pal[i]-1>mx)mx=i+pal[i]-1,id=i;
            ans=(ans+(pal[i]>>1))%mod;
            l[i-pal[i]+1]++;l[i+1]--;
            r[i]++;r[i+pal[i]]--;
        }
    }
    int main()
    {
        scanf("%d",&len);
        scanf("%s",t);
        init();
        manacher();
        LL inv=quick((LL)2,(LL)mod-2);
        ans=(ans*(ans-1)/2)%mod;
        LL sum=0;//表示结尾为[1,i) 
        for(int i=1;i<=len;++i)
        {
            l[i]+=l[i-1];r[i]+=r[i-1];
            if(i&1)continue;
            ans=(ans-(sum*l[i]))%mod;
            ans=(ans+mod)%mod;
            sum=(sum+r[i])%mod;
        }
        printf("%lld
    ",ans);
    } 
    /*
    */
    CF13E
  • 相关阅读:
    【总结】st表
    【luogu】p2024 食物链
    【总结】stl(以后还会慢慢补上
    【总结】二叉堆
    【luogu】p1631 序列合并
    才子们博客地址
    Lemon测评软件使用说明 (对比cena)
    Cena编译器的使用 及任大佬和禚大佬解释(O2优化、C++11特性、开栈)值得大家学习
    编程求100内的素数
    【关于德育和道德方面】
  • 原文地址:https://www.cnblogs.com/yyys-/p/11750876.html
Copyright © 2011-2022 走看看