A1393. Palisection
时间限制:
2.0s 内存限制:
256.0MB
试题来源
CODEFORCES 17E
问题描述
给你一个长度 n (1 ≤ n ≤ 2·10
6) 的只由小写字母组成的字符串s。
我们考虑s的所有连续且回文的子串集合P。位置不同但内容相同的两个串算作不同。
问从P中选出两个串且他们在s中有公共位置的方法数有几个?
我们考虑s的所有连续且回文的子串集合P。位置不同但内容相同的两个串算作不同。
问从P中选出两个串且他们在s中有公共位置的方法数有几个?
输入格式
第一行一个整数n
第二行字符串s
第二行字符串s
输出格式
一行答案,输出结果对51123987取余。
样例输入
4
babb
babb
样例输出
6
数据规模和约定
10%的数据 n<=5
15%的数据 n<=100
25%的数据 n<=1000
50%的数据 n<= 2·10 6
15%的数据 n<=100
25%的数据 n<=1000
50%的数据 n<= 2·10 6
思路来自
鸟神ORZ
有点坑的是相乘的时候会超int,所以要强制转换一下到long long 否则50分。。。
ac代码
提交序号 | 提交时间 | 语言 | 结果 | 得分 | 风格分? | 时间使用 | 空间使用 |
---|---|---|---|---|---|---|---|
|
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#define mod 51123987
#define maxn 2000005
#define N 26
#define LL long long
using namespace std;
struct P_tree
{
int next[maxn][N];
int fail[maxn];
int cnt[maxn];
int len[maxn];
int s[maxn];
int n;
int last;
int p;
int num[maxn];
int newnode(int l)
{
for(int i=0;i<N;i++)
next[p][i]=0;
cnt[p]=0;
len[p]=l;
return p++;
}
void init()
{
p=0;
newnode(0);
newnode(-1);
last=0;
n=0;
s[n]=-1;
fail[0]=1;
}
int get_fail(int x)
{
while(s[n-len[x]-1]!=s[n])
x=fail[x];
return x;
}
int add(int c)
{
c-='a';
s[++n]=c;
int cur=get_fail(last);
if(!next[cur][c])
{
int now=newnode(len[cur]+2);
fail[now]=next[get_fail(fail[cur])][c];
next[cur][c]=now;
num[now]=num[fail[now]]+1;
}
last=next[cur][c];
cnt[last]++;
return num[last];
}
int count()
{
int i;
int ans=0;
for(i=p-1;i>=1;i--)/
{
cnt[fail[i]]=(cnt[fail[i]]+cnt[i])%mod;
ans=(ans+cnt[i])%mod;
}
return ans;
}
}T;
char str[maxn];
int n;
int sf[maxn];
void solve()
{
int ans=0;
T.init();
sf[n]=0;
int i;
for(i=n-1;i>=0;i--)
{
sf[i]=(sf[i+1]+T.add(str[i]))%mod;
}
T.init();
for(i=0;i<n;i++)
{
ans=(ans+((LL)T.add(str[i])*sf[i+1])%mod)%mod;
}
int res=T.count();
res=(((LL)res*(res-1))/2)%mod;
printf("%d\n",((res-ans)+mod)%mod);
}
int main()
{
// int n;
while(scanf("%d",&n)!=EOF)
{
scanf("%s",str);
solve();
}
}