• [APIO2014]回文串


    V.[APIO2014]回文串

    具体分析详见本人的SA题解,这里主要是讲解使用SAM求子串出现次数的方法。

    SAM应用3:查询一个子串的出现次数。

    这个思想很简单,只需要找到该子串对应的 \(\text{endpos}\) 等价类是哪个即可。

    我们考虑记录 \(id_i\) 表示以位置 \(i\) 结尾的后缀所对应等价类的编号。然后,假设我们要查询子串 \([l,r]\),就找到 \(id_r\),然后往上倍增地跳父亲,直到跳到长度恰好不大于 \(r-l+1\) 的那个类,即为此子串所在的类。

    使用马拉车求出所有极大回文串,复杂度 \(O\Big(n(\log n+|\Sigma|)\Big)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=300002;
    typedef long long ll;
    int cnt=1,ch[N<<1][26],fa[N<<1],len[N<<1],sz[N<<1];
    int Add(int x,int c){
    	int xx=++cnt;len[xx]=len[x]+1;
    	sz[xx]=1;
    	for(;x&&!ch[x][c];x=fa[x])ch[x][c]=xx;
    	if(!x){fa[xx]=1;return xx;}
    	int y=ch[x][c];
    	if(len[y]==len[x]+1){fa[xx]=y;return xx;}
    	int yy=++cnt;fa[yy]=fa[y];
    	for(int i=0;i<26;i++)ch[yy][i]=ch[y][i];
    	len[yy]=len[x]+1;
    	fa[xx]=fa[y]=yy;
    	for(;x&&ch[x][c]==y;x=fa[x])ch[x][c]=yy;
    	return xx;
    }
    vector<int>v[N<<1];
    void dfs(int x){for(auto y:v[x])dfs(y),sz[x]+=sz[y];}
    int n,id[N];
    ll val(int l,int r){
    	l=max(l,0),r=min(r,n-1);
    	int x=id[r];
    	for(int i=18;i>=0;i--)if(ch[x][i]&&len[ch[x][i]]>=r-l+1)x=ch[x][i];
    	return 1ll*sz[x]*(r-l+1);
    }
    char s[N],ss[N<<1];
    int rad[N<<1];
    ll res;
    void Manacher(){
    	int T=0,ret=0;
    	ss[T++]='$';
    	for(int i=0;i<n;i++)ss[T++]=s[i],ss[T++]='$';
    	int Centre=-1,Rpos=-1;
    	for(int i=0;i<T;i++){
    		if(i<=Rpos)rad[i]=min(Rpos-i,rad[2*Centre-i]);
    		while(i-rad[i]>=0&&i+rad[i]<T&&ss[i-rad[i]]==ss[i+rad[i]])rad[i]++;
    		if(Rpos<i+rad[i])Centre=i,Rpos=i+rad[i];
    		res=max(res,val((i-rad[i]+1)>>1,(i+rad[i]-2)>>1));
    	}
    }
    int main(){
    	scanf("%s",s),n=strlen(s);
    	for(int i=0,las=1;i<n;i++)id[i]=las=Add(las,s[i]-'a');
    	for(int i=1;i<=cnt;i++)ch[i][0]=fa[i],v[fa[i]].push_back(i);
    	for(int j=1;j<=18;j++)for(int i=1;i<=cnt;i++)ch[i][j]=ch[ch[i][j-1]][j-1];
    	dfs(1);
    	Manacher();
    	printf("%lld\n",res);
    	return 0;
    }
    

  • 相关阅读:
    抓取用户openid
    getaccesstoken方法
    https_request请求接口返回数据
    composer安装
    Linux下mysql数据库root无法登录的情况
    nginx安装
    shell脚本采用crontab定时备份数据库日志
    Python之元类详细解析
    Python面向对象之封装、property特性、绑定方法与非绑定方法
    Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式
  • 原文地址:https://www.cnblogs.com/Troverld/p/14605682.html
Copyright © 2020-2023  润新知