ACM-ICPC Nanjing Onsite 2018 M - (扩展KMP+manacher算法)

题目链接:Mediocre String Problem - 题库 - 计蒜客

解题思路;

对于s串的某个点i的贡献就是以i点为左边界在s串上有多少种回文串(记为x)这些回文串可以插在中间,那么右端自然是t的前缀,左端就是t前缀的倒置。

求t前缀的倒置不就是将s倒过来看,取求s中的i节点为开头与t的最长前缀公共子串长度吗?(长度记为y)所以这个可以倒过来后用扩展KMP求得。之后对于i点的贡献就是x*y(y是倒置后的相应位置)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e6 + 10;
int dp[mx*2],nxt[mx],extend[mx];
int sum[mx];
char s[mx],t[mx],str[mx*2];
void E_init(int len)
{
	nxt[0] = len;
	extend[0] = nxt[1] = 0;
    int j = 0,k = 1;
    while(t[k++]==t[j++]) nxt[1]++;	
    j = k = 0;
    while(j<len&&t[j++]==s[k++]) extend[0]++;
}
int M_init(char *p)
{
	int len = 0;
	str[len++] = '$';
	str[len++] = '#'; 
	for(int i=0;p[i];i++)
	{
		str[len++] = p[i];
		str[len++] = '#';
	}
	return len;
}
void manacher(char *p)
{
	int len = M_init(p);
	int Max = 0,id,r;
	for(int i=1;i<len;i++){
		if(i<Max) dp[i] = min(Max-i,dp[2*id-i]);
		else dp[i] = 1;
		while(str[i+dp[i]]==str[i-dp[i]]) dp[i]++;
		if(i+dp[i]>Max) id = i,Max = i + dp[i];
	}
	for(int i=2;i<len;i++){
		if(i=='#') r = (i-3)/2 + 1;
		else r = (i-2)/2 + 1;
		sum[r-dp[i]/2]++,sum[r]--;
	}
	for(int i=1;p[i];i++) sum[i] += sum[i-1];
}
void Get(char *c,int len,int *tmp,int po,int pos)
{
    int j,k;
    for(int i=1;i<len;i++){
        int lon = nxt[i-po];
        if(i+lon<pos) tmp[i] = lon;
        else{
            if(pos<i) pos = i;
            tmp[i] = pos - i;//先确定他是可以到达p的
            j = pos,k = pos - i;
            while(j<len&&c[j++]==t[k++]) tmp[i]++;//然后向后继续扩展
            po = i,pos = i + tmp[i];//更新po和pos
        }
    }
}
int main()
{
	scanf("%s%s",s,t);
	int Slen = strlen(s);
	int Tlen = strlen(t);
	manacher(s);
	reverse(s,s+Slen);
	E_init(Tlen);
	Get(t,Tlen,nxt,1,1+nxt[1]);
	Get(s,Slen,extend,0,extend[0]);
	ll ans = 0;
	for(int i=1;i<Slen;i++) ans += 1ll*sum[i]*extend[Slen-i];
	printf("%lld\n",ans);
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值