双回文pam写法

Lx神犇说我这种写法就是核弹打蚊子。。。但是我不会马拉车啊。而且这个算法也是我上通技课的时候突然想到的。。。首先pam这个东西非常神而且特别好记忆(虽然一开始被坑了一下)基本上熟了之后敲板子都不怎么要动脑子。而且功能异常强大。但是对于这道题我们构想双回文首先他肯定要是四的倍数其次他要是回文串。对于这两点pam做起来都很容易。然后怎么判断在回文串中平分之后还是回文串呢。显然我们应该到失陪边那里找线索。然后显然当l[x]=k; l[fail[fail[fail…..fail[x]],也就是某个类似于祖先的东西值等于k/2那么这件事就搞定了。如何快速找到=k/2的祖先呢。首先根据失陪边重新建造一棵树这是很显然的。然后我是写了一个树上倍增解决的。还有一点值得一提。这题128mb竟然害我一开始mle…后来把pam数组公用了才卡过内存。。。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<cmath>

#include<cstdlib>

#include<vector>

using namespace std;

#define maxn 500005

#define forup(i,a,b) for(inti=a;i<=b;i++)

#define fordown(i,a,b) for(inti=a;i>=b;i--)

#define pb push_back

#define a fa

vector<int> g[maxn];

int deep[maxn];

char s[maxn];

int n;

        intfa[maxn][26];

struct pam

{               intcnt,last;

        intfail[maxn],l[maxn];

        pam(){

            cnt=1;fail[0]=fail[1]=1;l[1]=-1;

            g[1].pb(0);

        }

       

        voidextend(int c,int n)

        {int p=last;

          while(s[n]!=s[n-l[p]-1])

        {   p=fail[p];}

          if(!a[p][c])

           {cnt++;int k=fail[p];

             l[cnt]=l[p]+2;

             while(s[n]!=s[n-l[k]-1])  k=fail[k];

      fail[cnt]=a[k][c]; a[p][c]=cnt;//这两句话千万不要写反了。因为在边界情况下写反会出问题。。。具体问题要认真调试才好分析。。。反正记牢就好

           g[fail[cnt]].pb(cnt);

           }

             last=a[p][c];

        }

       

       

}pam;

/

void dfs(int x)

{

   for(int i=1; i<24; i++)

    {

       if(deep[x]<(1<<i))break;

       fa[x][i]=fa[fa[x][i-1]][i-1];

    }

 for(int i=0;i<g[x].size();i++)

    {

       int v=g[x][i];

       fa[v][0]=x;

       deep[v]=deep[x]+1;

       dfs(v);

    }

   

}

bool work(int x)

{ int tmp=pam.l[x]>>1;

 

        while(true)

                  { int i; for(i=0;i<24;i++)

                     { if(deep[x]<(i<<i)) break;

                       if(pam.l[fa[x][i]]<tmp)  break;

                         }

                         i--;

                         if(i==-1)

             {if(pam.l[x]==tmp) return 1;

               else  return 0;

                  }

         x=fa[x][i];

        }

}

 

int main()

{ cin>>n;

 scanf("%s",s+1);

 forup(i,1,n)

  {pam.extend(s[i]-'a',i);

   }

 /* forup(i,0,pam.cnt)

  {cout<<i<<endl;

  for(int j=0;j<g[i].size();j++)

  {  cout<<' '<<g[i][j];

   }

   cout<<endl;}*/

   memset(fa,0,sizeof(0));

        dfs(1);

        intans=0;

forup(i,2,pam.cnt)  

{ //cout<<pam.l[i]<<endl;

 if(pam.l[i]%4==0&&work(i))

 ans=max(pam.l[i],ans);

}

//cout<<pam.cnt<<endl;

        cout<<ans;

        return0;

 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值