• 题解 CF17E 【Palisection】


    卡空间PAM,2010没有PAM,所以都是马拉车

    众所周知,PAM拥有十分优秀的时间复杂度,但空间复杂度lj得不行

    但这题卡空间,所以得用到邻接链表PAM

    先讲思路

    题目要求相交的回文子串对,这很难做

    于是我们求补集,求不相交的回文子串对,再用总数减即可

    求法和上文的最长双回文子串 类似

    正反建一次PAM,存该位置结尾的回文子串个数,然后加法改乘法

    自己领悟一下,挺简单的。

    现在讲一下邻接链表PAM

    注意:邻接链表PAM不是使空间变小了,而是用时间换空间

    我们记边结构体(line)

    (3)个信息:(nx,to,w) 分别表示上一条边,这条边通向的节点编号,这条边是代表哪个字符

    数组(fir[i])表示(i)伸出的最后一条边的编号(头插式

    当我们要寻找(u)(v)儿子

    我们就像邻接链表一样找,直到有一条边的(w==v)为止

    找不到记得指根

    int getson(int u,int v){
    	for(int i=u;i!=-1;i=l[i].nx)
    		if(l[i].w==v)return l[i].to;
    	return -1;
    }
    

    建点的时候把边建上

    void insert(int u,int i){
    	int Fail=getfail(pre,i),ls=getfail(fail[Fail],i);
    	if(getson(fir[Fail],u)==-1){
    		if(getson(fir[ls],u)==-1)fail[++tot]=0;		//找不到指根
    		else fail[++tot]=getson(fir[ls],u);	//找到了
    		l[++cnt]=(line){fir[Fail],tot,u};fir[Fail]=cnt;		//加边
    		len[tot]=len[Fail]+2;
    		ans[tot]=ans[fail[tot]]+1;		//结尾回文子串个数
    		pre=tot;
    	}else 
    	pre=getson(fir[Fail],u);
    }
    

    然鹅事实上你仍然过不了,你还要继续压空间,省掉一堆数组就可以过啦!

    总代码:

    #include<bits/stdc++.h>
    #define maxn 2000005
    #define mod 51123987
    using namespace std;
    char s[maxn];
    int slen,b[maxn];
    long long res;
    int fail[maxn],len[maxn],ans[maxn],fir[maxn];
    struct line{int nx,to,w;}l[maxn];
    int tot,pre,cnt;
    void init(){
    	memset(fir,-1,sizeof(fir));cnt=0;
    	fail[0]=1;len[1]=-1;tot=1;pre=0;
    }
    int getfail(int x,int i){
    	while(i-len[x]-1<0||s[i-len[x]-1]!=s[i])x=fail[x];
    	return x;
    }
    int getson(int u,int v){
    	for(int i=u;i!=-1;i=l[i].nx)
    		if(l[i].w==v)return l[i].to;
    	return -1;
    }
    void insert(int u,int i){
    	int Fail=getfail(pre,i),ls=getfail(fail[Fail],i);
    	if(getson(fir[Fail],u)==-1){
    		if(getson(fir[ls],u)==-1)fail[++tot]=0;
    		else fail[++tot]=getson(fir[ls],u);
    		l[++cnt]=(line){fir[Fail],tot,u};fir[Fail]=cnt;
    		len[tot]=len[Fail]+2;
    		ans[tot]=ans[fail[tot]]+1;
    		pre=tot;
    	}else 
    	pre=getson(fir[Fail],u);
    }
    int main(){
    	int n;
    	scanf("%d",&n);
    	scanf("%s",s);slen=strlen(s);init();
    	reverse(s,s+slen);
    	for(int i=0;i<slen;i++)insert(s[i]-'a',i),b[slen-i-1]=ans[pre];
    	for(int i=slen-1;i>=0;i--)b[i]+=b[i+1],b[i]%=mod;
    	reverse(s,s+slen);init();
    	for(int i=0;i<slen-1;i++){
    		insert(s[i]-'a',i);int x=ans[pre];
    		res+=(1ll*x*b[i+1])%mod,res%=mod;
    	}
    	printf("%lld
    ",((1ll*b[0]*(b[0]-1)/2ll)%mod-res+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    javascript 数字时钟
    ubuntu下键盘背景灯光设置
    使用百度地图SDK
    ListView 的Item状态改变和保存
    继续Jsoup 正方教务系统的教学质量评价一键好评
    Java下的可视化开发工具使用 WindowBuilder Pro
    js 数组排序
    js数组去重
    js call() apply()
    [总结] js的2种继承方式详解
  • 原文地址:https://www.cnblogs.com/hyfhaha/p/13694775.html
Copyright © 2020-2023  润新知