给你个三元组(i,j,k) 满足1≤i≤j< k≤length(S), S[i..j] and S[j+1..k] are all palindrome strings,问对于所有这个三元组,i*k和是多少。
先跑一遍manacher不多说。
我在这里处理了四个数组:C1,C2,C3,C4
C1:代表对于下标i的点,他所在的回文串(回文串在他右边)中心下标*2的和
C2:代表对于下标i的点,他所在的回文串个数(回文串在他右边)
C3:代表对于下标i的点,他所在的回文串(回文串在他左边)中心下标*2的和
C4:代表对于下标i的点,他所在的回文串个数(回文串在他左边)
本可以O(N)时间处理出这四个数组,结果比赛时候犯傻了用了四个树状数组,然后GG
因为处理这四个数组虽然是对区间的更新,但是并没有查询,只要算出结果就行,所以可以O(N)出来,mdzz
我的想法是把manacher上的结果映射到原来的字符串上进行计数,然后写写懵B了,lv男神直接在manacher上数组上做了计数(666)
不懂请看lv博客(地址:http://blog.csdn.net/a409082492)
#include
#include
#include
using namespace std;
const int mod = 1000000007;
const int maxn=1000010;
typedef long long ll;
char str[maxn];//原字符串
char tmp[maxn<<1];//转换后的字符串
int Len[maxn<<1];
int sl;
//转换原始串
inline int INIT(char *st)
{
int i,len=strlen(st);
sl = len;
tmp[0]='@';//字符串开头增加一个特殊字符,防止越界
for(i=1;i<=2*len;i+=2)
{
tmp[i]='#';
tmp[i+1]=st[i/2];
}
tmp[2*len+1]='#';
tmp[2*len+2]='$';//字符串结尾加一个字符,防止越界
tmp[2*len+3]=0;
return 2*len+1;//返回转换字符串的长度
}
//Manacher算法计算过程
inline int MANACHER(char *st,int len)
{
int mx=0,ans=0,po=0;//mx即为当前计算回文串最右边字符的最大值
for(int i=1;i<=len;i++)
{
if(mx>i)
Len[i]=min(mx-i,Len[2*po-i]);//在Len[j]和mx-i中取个小
else
Len[i]=1;//如果i>=mx,要从头开始匹配
while(st[i-Len[i]]==st[i+Len[i]])
Len[i]++;
if(Len[i]+i>mx)//若新计算的回文串右端点位置大于mx,要更新po和mx的值
{
mx=Len[i]+i;
po=i;
}
ans=max(ans,Len[i]);
}
return ans-1;//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
}
const int SIZE = maxn << 1;
int C1[SIZE], C2[SIZE], C3[SIZE], C4[SIZE];
inline void modify1(int l,int r,int v)
{
// printf("l=%d r=%d v=%d\n",l,r,v);
if(l > r) return;
C1[l] += v;
C1[l] %= mod;
C1[r+1] -= v;
C1[r+1] %= mod;
}
inline void modify2(int l,int r,int v)
{
if(l > r) return;
C2[l] += v;
C2[l] %= mod;
C2[r+1] -= v;
C2[r+1] %= mod;
}
inline void modify3(int l,int r,int v)
{
if(l > r) return;
C3[l] += v;
C3[l] %= mod;
C3[r+1] -= v;
C3[r+1] %= mod;
}
inline void modify4(int l,int r,int v)
{
if(l > r) return;
C4[l] += v;
C4[l] %= mod;
C4[r+1] -= v;
C4[r+1] %= mod;
}
inline void init()
{
memset(C1,0,sizeof(C1));
memset(C2,0,sizeof(C2));
memset(C3,0,sizeof(C3));
memset(C4,0,sizeof(C4));
}
int main() {
while(~scanf("%s",str)) {
int l = INIT(str);
MANACHER(tmp, l);
init();
int res = 0;
for(int i = l; i >= 1; i--) {
modify1((i-Len[i]+1),i,i);
modify3((i-Len[i]+1),i,1);
}
for(int i = 1; i <= l; i++) {
modify2(i,(i+Len[i]-1),i);
modify4(i,(i+Len[i]-1),1);
}
for(int i = 1; i <= l; i++) C1[i] += C1[i-1], C1[i] =(mod+C1[i])%mod;
for(int i = 1; i <= l; i++) C2[i] += C2[i-1], C2[i] =(mod+C2[i])%mod;
for(int i = 1; i <= l; i++) C3[i] += C3[i-1], C3[i] =(mod+C3[i])%mod;
for(int i = 1; i <= l; i++) C4[i] += C4[i-1], C4[i] =(mod+C4[i])%mod;
for(int i = 2,j = 0; i < l-1; i+=2,j++) {
int lt = ((C1[i+2] - (ll)C3[i+2]*((i+2)/2))%mod + mod) % mod;
int rt = ((C2[i] - (ll)C4[i]*(i/2))%mod + mod ) % mod;
res += ((ll)lt * (ll)rt) %mod;
res %= mod;
}
printf("%d\n",res);
}
}