您的位置:首页 > 其它

Hdu 5785 Interesting(给你一个字符串,你可以选择这个字符串的一个子串,记为s[l...r] 你可以选择一个k(i<=k< j)将这个子串划分成两半,如果这两半都是回文串,那么答案)

2016-08-02 19:54 399 查看
传送门:Hdu 5785 Interesting

给你一个字符串,你可以选择这个字符串的一个子串,记为s[l…r]

你可以选择一个k(i<=k< j)将这个子串划分成两半,如果这两半都是回文串,那么答案加上l*r,

同一个子串可以被划分多次,问最后的答案为多少。

思路:首先我们先对原来的子串进行一次manacher,那么假设以i这个点为分割点

分成s[l…i]和s[i+1…r],那么这个对答案的贡献便为(x1+x2+…+xn)*(y1+y2+…+ym)

x1,x2…xn表示和i点为终点构成回文串的起点,y1,y2,…ym表示和j点为起点构成回文串的终点

接下来的工作便是统计x1+…+xn和y1+…+yn

manacher中的p[i]表示以i为中心的(包含i这个字符的回文串半径长)

num1的前缀和表示以这个点为结尾的回文串的总个数,cnt1[i]表示到每个位置为中心的位置的总和(用double表示)

那么x[i]等于2*cnt1[i]-i*num1[i]

对于i为偶数的那些位置,num1[i/2]++,num1[i/2+p[i]/4+1]–;(对应回原来的字符串中),

同时记录一下cnt1[i/2]+=i/2,cnt1[i/2+p[i]/4+1]-=i/2;(表示到每个位置为中心的位置的总和)

对于i为奇数的那些位置,num1[i/2+1]++,num1[i/2+p[i]/4+1]–;

同时记录一下,cnt1[i/2+1]+=1.0*i/2,cnt1[i/2+p[i]/4+1]-=1.0*i/2

num2前缀和表示以这个点为开头的回文串的总个数,cnt2[i]表示到每个位置为中心的位置的总和(用double表示)

那么y[i]等于2*cnt2[i]-i*num2[i]

对于i为偶数的那些位置,num2[i/2+1]–,num2[i/2-p[i]/4]++;(对应回原来的字符串中),

同时记录一下cnt2[i/2-p[i]/4]+=1.0*i/2,cnt2[i/2+1]-=1.0*i/2

对于i为奇数的那些位置,num2[i/2+1]–,num2[(i+1)/2-p[i]/4]++;

同时记录一下cnt2[(i+1)/2-p[i]/4]+=1.0*i/2,cnt2[i/2+1]-=1.0*i/2

又因为cnt最终都是要乘以2的,所以刚开始的除以2就不要了

#include<bits/stdc++.h>
using namespace std;
const int maxn=2001000;
const int MOD=1000000007;
char s[maxn],str[maxn];
int p[maxn];
long long num1[maxn],num2[maxn];
long long cnt1[maxn],cnt2[maxn];

int main(){
while(scanf("%s",str+1)!=EOF){
int len=strlen(str+1);
for(int i=1;i<=len+1;i++)
s[i*2]=str[i],s[i*2-1]='#';
s[0]='*';
int id=0,maxv=0;
memset(cnt1,0,sizeof(cnt1));
memset(cnt2,0,sizeof(cnt2));
memset(num1,0,sizeof(num1));
memset(num2,0,sizeof(num2));
memset(p,0,sizeof(p));
for(int i=1;i<=len*2;i++){
if(p[id]+id>i)
p[i]=min(p[2*id-i],p[id]+id-i);
else
p[i]=1;
while(s[i-p[i]]==s[i+p[i]])
++p[i];
if(i+p[i]>id+p[id])
id=i;
}
long long ans=0;
for(int i=1;i<=len*2;i++){
p[i]=p[i]*2-1;
if(i&1){
num1[i/2+1]++,num1[i/2+p[i]/4+1]--;
cnt1[i/2+1]+=i,cnt1[i/2+p[i]/4+1]-=i;
num2[i/2+1]--,num2[(i+1)/2-p[i]/4]++;
cnt2[(i+1)/2-p[i]/4]+=i,cnt2[i/2+1]-=i;
}
else{
num1[i/2]++,num1[i/2+p[i]/4+1]--;
cnt1[i/2]+=i,cnt1[i/2+p[i]/4+1]-=i;
num2[i/2+1]--,num2[i/2-p[i]/4]++;
cnt2[i/2-p[i]/4]+=i,cnt2[i/2+1]-=i;
}
}
for(int i=1;i<=len;i++)
cnt1[i]+=cnt1[i-1],num1[i]+=num1[i-1],cnt2[i]+=cnt2[i-1],num2[i]+=num2[i-1];
for(int i=1;i<len;i++)
ans=(ans+( (cnt1[i]-num1[i]*i)%MOD*( (cnt2[i+1]-num2[i+1]*(i+1)) %MOD))%MOD)%MOD;
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐