zoukankan      html  css  js  c++  java
  • 「专题总结」回文自动机

    模板
    
    #include<cstdio>
    #include<cstring>
    #include
    #define reg register
    #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
    using namespace std;
    const int N=100005;
    int len,n;
    char s[N];
    struct PAM{
    	int las,num;
    	int len[N],son[N][26],fail[N],ed[N];
    	void init(){
    		las=num=1;
    		len[1]=-1;
    		fail[0]=fail[1]=1;
    	}
    	int getfail(int x){
    		while(s[n-len[x]-1]^s[n])x=fail[x];
    		return x;
    	}
    	void extend(int c){
    		int u=getfail(las);
    		if(!son[u][c]){
    			int v=++num;
    			len[v]=len[u]+2;
    			fail[v]=son[getfail(fail[u])][c];
    			son[u][c]=num;
    		}
    		las=son[u][c];
    		ed[n]=len[las];
    	}
    }pam1,pam2;
    int main()
    {
    	scanf("%s",s+1);len=strlen(s+1);
    	pam1.init();pam2.init();
    	for(n=1;n<=len;++n)pam1.extend(s[n]-'a');
    	n=0;reverse(s+1,s+len+1);
    	for(n=1;n<=len;++n)pam2.extend(s[n]-'a');
    	int ans=0;
    	F(i,2,len)ans=max(ans,pam1.ed[i-1]+pam2.ed[len-i+1]);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    A.双倍回文

    维护trans指针,定义和fail不同在于有长度缩小一半的限制,求法也类似。
    必须从fa的trans跳,不然复杂度可卡到(n^2) (aaaaa...) 。

    B.最长双回文串

    增量构造完i时,len[las]是以i结尾的最长回文串。
    所以正反都建一边,枚举分界点两侧取max。

    C. I Love Palindrome String

    类似双倍回文,不同在于要求方案数
    由fail指针定义,知某个回文串的出现次数为其在fail树上的子树siz和
    拓扑统计,由于(fail[i] leq i),所以按PAM上的编号倒序扫一边即可。
    特判单个字符。

    D. Antisymmetry

    “反对称串”是两侧对称位置的数完全不同的串
    “回文串” 是两侧对称位置的数完全相同的串
    考虑魔改一下PAM的判断条件。
    但由于PAM的实现特别鬼畜,有很多之前精妙地避开的边界现在必须特判了。
    奇数长度一定不合法,只存偶根。
    偶根长度设为-1便于getfail
    没有单个字符的情况,直接return

    E. 对称的正方形

    并不会PAM做法。
    正解是二分+二维hash check
    预处理三个方向的二维hash。
    枚举中间点,按奇偶分类讨论。
    固定中心后边长合法具有单调性,二分一半边长。
    三个hash值比较check。
    类似二维前缀和,预处理pow,见代码

    二维hash
    
    #include<cstdio>
    #include<algorithm>
    #define unll unsigned long long
    #define reg register
    #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
    using namespace std;
    int read();
    const int N=1005;
    int n,m;
    int z0[N][N],z1[N][N],z2[N][N];
    unll bs1[N],bs2[N],h0[N][N],h1[N][N],h2[N][N];
    void Hash(int z[N][N],unll h[N][N]){
    	F(i,1,n)F(j,1,m)h[i][j]=h[i][j-1]*bs1[1]+z[i][j];
    	F(i,1,n)F(j,1,m)h[i][j]+=h[i-1][j]*bs2[1];
    }
    unll ask(unll h[N][N],int a,int b,int x,int y){
    	return h[x][y]-h[x][b-1]*bs1[y-b+1]-h[a-1][y]*bs2[x-a+1]+h[a-1][b-1]*bs1[y-b+1]*bs2[x-a+1];
    }
    bool check1(int x,int y,int t){
    	unll w0,w1,w2;
    	w0=ask(h0,x-t+1,y-t+1,x+t-1,y+t-1);
    	y=m-y+1;
    	w1=ask(h1,x-t+1,y-t+1,x+t-1,y+t-1);
    	y=m-y+1;x=n-x+1;
    	w2=ask(h2,x-t+1,y-t+1,x+t-1,y+t-1);
    	return w0==w1&&w1==w2;
    }
    bool check2(int x,int y,int t){
    	unll w0,w1,w2;
    	w0=ask(h0,x-t+1,y-t+1,x+t,y+t);
    	y=m-y;
    	w1=ask(h1,x-t+1,y-t+1,x+t,y+t);
    	y=m-y;x=n-x;
    	w2=ask(h2,x-t+1,y-t+1,x+t,y+t);
    	return w0==w1&&w1==w2;
    }
    int main(){
    	n=read(),m=read();
    	F(i,1,n)F(j,1,m)z0[i][j]=z1[i][m-j+1]=z2[n-i+1][j]=read()+1;
    	bs1[0]=bs2[0]=1ull;
    	F(i,1,m)bs1[i]=bs1[i-1]*2333ull;
    	F(i,1,n)bs2[i]=bs2[i-1]*131ull;
    	Hash(z0,h0);
    	Hash(z1,h1);
    	Hash(z2,h2);
    	int ans=0;
    	F(i,1,n)F(j,1,m){
    		int l,r,mid;
    		l=1,r=min(min(i,n-i+1),min(j,m-j+1));
    		while(l>1;
    			if(check1(i,j,mid))l=mid;
    			else r=mid-1;
    		}
    		ans+=l;
    		l=0,r=min(min(i,n-i),min(j,m-j));
    		while(l>1;
    			if(check2(i,j,mid))l=mid;
    			else r=mid-1;
    		}
    		ans+=l;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    int read()
    {
    	int x=0,fh=1;char tc=getchar();
    	while(tc<'0'||tc>'9'){if(tc=='-')fh=-1;tc=getchar();}
    	while(tc>='0'&&tc<='9')x=(x<<3)+(x<<1)+(tc^48),tc=getchar();
    	return fh*x;
    }
    
  • 相关阅读:
    redis 学习(一)
    spring 学习总结(一)
    Struts2 学习(三)
    Python3 高级特性
    Python3 模块
    Python3 函数式编程
    Python3 函数
    Python3 列表
    Python3 字符编码
    Java Servlet 回顾
  • 原文地址:https://www.cnblogs.com/hzoi-yzh/p/12101095.html
Copyright © 2011-2022 走看看