HDU 5785 Interesting
题目链接:点击打开链接
题目大意:有一个长度为n的串( n≤106 ),对于 0<i≤j<k≤n ,如果 [i,j] 和 [j+1,k] 都是回文串,则对答案的贡献为 i∗k 。求最后的答案,mod 109+7 。
题解:
首先用Manacher处理出每个字符的回文半径。如果用
L[i]
表示以
i
结尾的回文串的左端点坐标值之和,
L[i]=2∗∑j−k∗i
其中
j
是包含这题可以直接在Manacher处理的回文半径上直接计算,对于 i−l+1≤j≤i ,对 L[i] 的贡献为 2∗i2−j2=i−j2 ,对于对称轴为#的情况同样适用。因此
L[i]=∑j−k∗i2
在计算最后的答案时只要每次+=2即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
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;
//转换原始串
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算法计算过程
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];
void init()
{
memset(C1,0,sizeof(C1));
memset(C2,0,sizeof(C2));
memset(C3,0,sizeof(C3));
memset(C4,0,sizeof(C4));
}
void add(int l,int r,int c[],int v){
c[l] += v;
c[l] %= mod;
c[r+1] += -v;
c[r+1] %= mod;
}
void update(int n,int c[]){
for(int i = 1;i <= n;i++){//更新
c[i] += c[i-1];
c[i] %= mod;
}
for(int i = 1;i <= n;i++){//求前缀和
c[i] += c[i-1];
c[i] %= mod;
}
}
int query(int l,int r,int c[]){
int ret = (c[r]-c[l-1]+mod)%mod;
return ret;
}
int main() {
while(~scanf("%s",str)) {
int l = INIT(str);
MANACHER(tmp, l);
init();
int res = 0;
for(int i = l; i >= 1; i--) {
//printf("i=%d ",i);
add((i-Len[i]+1),i,C1,i);
add((i-Len[i]+1),i,C3,1);
}
for(int i = 1; i <= l; i++) {
add(i,(i+Len[i]-1),C2,i);
add(i,(i+Len[i]-1),C4,1);
}
update(l,C1);
update(l,C2);
update(l,C3);
update(l,C4);
for(int i = 2,j = 0; i < l-1; i+=2,j++) {
//printf("%d\n",i);
int lt = ((query(i+2,i+2,C1) - (ll)query(i+2,i+2,C3)*((i+2)/2))%mod + mod) % mod;
//left[j] = lt;
int rt = ((query(i,i,C2) - (ll)query(i,i,C4)*(i/2))%mod + mod ) % mod;
//right[j] = rt;
//printf("q1=%d q2=%d q3=%d q4=%d\n",query(i,i,C1),query(i,i,C2),query(i,i,C3),query(i,i,C4));
//printf("%d %d\n",lt,rt);
res += ((ll)lt * (ll)rt) %mod;
res %= mod;
}
//for(int i = 0;i < 3;i++) printf("%d ",left[i]); printf("\n");
//for(int i = 0;i < 3;i++) printf("%d ",right[i]);
//printf("\n");
printf("%d\n",res);
}
}