zoukankan      html  css  js  c++  java
  • 【CF17E】Palisection(回文树)

    【CF17E】Palisection(回文树)

    题面

    洛谷

    题解

    题意:
    求有重叠部分的回文子串对的数量

    所谓正难则反
    求出所有不重叠的即可
    求出以一个位置结束的回文串的数量
    和以一个位置为开始的回文串的数量
    然后对应的乘一下就行了
    求法我用的是回文树
    维护每个节点到根节点的距离,
    就是回文后缀的数量

    CF上的空间是(128MB)
    卡的很
    所以所有的连边考虑用邻接表来代替

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 2000020
    #define MOD 51123987
    int n,p1[MAX],p2[MAX],ans,dep[MAX];
    char s[MAX];
    struct Line{int v,next,w;}e[MAX];
    int cnt=1;
    int h[MAX];
    inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
    struct PT
    {
    	struct Node
    	{
    		int ff,len;
    	}t[MAX];
    	int tot,last;
    	void init()
    	{
    		for(int i=0;i<=tot;++i)
    		{
    			h[i]=0;
    			t[i].ff=t[i].len=0;
    		}
    		cnt=1;
    		last=0;
     		t[tot=1].len=-1;
    		t[0].ff=t[1].ff=1;
    	}
    	int nt(int k,int c)
    	{
    		for(int i=h[k];i;i=e[i].next)
    			if(e[i].w==c)return e[i].v;
    		return 0;
    	}		
    	void extend(int c,int n,char *s)
    	{
    		int p=last;
    		while(s[n-t[p].len-1]!=s[n])p=t[p].ff;
    		if(!nt(p,c))
    		{
    			int v=++tot,k=t[p].ff;
    			while(s[n-t[k].len-1]!=s[n])k=t[k].ff;
    			t[v].len=t[p].len+2;
    			t[v].ff=nt(k,c);
    			dep[v]=dep[t[v].ff]+1;
    			Add(p,v,c);
    		}
    		last=nt(p,c);
    	}
    }pt1;
    int main()
    {
     	scanf("%d",&n);
    	scanf("%s",s+1);
    	pt1.init();
    	for(int i=1;i<=n;++i)
    	{
    		pt1.extend(s[i]-97,i,s);
    		ans=(ans+(p1[i]=dep[pt1.last]))%MOD;
    	}
    	ans=1ll*ans*(ans-1)/2%MOD;
    	reverse(&s[1],&s[n+1]);
    	memset(dep,0,sizeof(dep));
    	pt1.init();
    	for(int i=1;i<=n;++i)
    	{
    		pt1.extend(s[i]-97,i,s);
    		p2[n-i+1]=dep[pt1.last];
    	}
    	for(int i=n;i;--i)(p2[i]+=p2[i+1])%=MOD;
    	for(int i=1;i<=n;++i)ans=(ans-1ll*p1[i]*p2[i+1]%MOD+MOD)%MOD;
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    wx.showToast 延时跳转~~~
    wx.request 获取不到post传递的值
    G,sql中select 如果太长,可以在后面放G,竖行显示~~~~
    用for语句从数组中剔除数据,注意,count,要放到for语句之外才行
    读代码还是读文档,来自知乎
    聊聊我对写好程序的认识
    open() 函数以 r+ 模式打开文件
    open()
    Python 流程控制:while
    Python 序列
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8463531.html
Copyright © 2011-2022 走看看