题目:给一串由0..9组成的数字字符串,求所有不同回文串的权值和。比如说“1121”这个串中有“1”,“2”,“11”,“121”三种回文串,他们的权值分别是1,2,11,121。最终输出ans=135
思路:昨天比赛时读题给读错了样例也没看怎么来的。写成了所有的回文串权值和。。。码完代码发现,玛德样例都不对,再读了一遍题,真是智障啊。
今天看到有大佬讨论马拉车+哈希的做法,(本菜鸡学的马拉车都搁浅了一年多了),就重新看了看kungbin的模板,写了一下。了解马拉车原理会发现它对这个题本身就有个剪枝(i 这个字符串往外扩的初始长度Mp[i]直接就是剪掉了1..Mp[i]长度之后的啦)。但是仍然会有重复的(我map去重T了),这里再去重的办法就很巧妙了%%%,然后具体算权值时hash预处理,然后O(1)查询就好
先贴一个manacher的模板
///求最长回文子串
const int MAXN=110010;
char Ma[MAXN*2];
int Mp[MAXN*2];
void Manacher(char s[],int len)
{
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++)
{
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++)
{
Mp[i]=mx>i?min(Mp[2*id−i],mx−i):1;
while(Ma[i+Mp[i]]==Ma[i−Mp[i]])
Mp[i]++;
if(i+Mp[i]>mx)
{
mx=i+Mp[i];
id=i;
}
}
}
/*
* abaaba
* i: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
* Ma[i]: $ # a # b # a # a # b # a #
* Mp[i]: 1 1 2 1 4 1 2 7 2 1 4 1 2 1
*/
char s[MAXN];
int main()
{
while(scanf("%s",s)==1)
{
int len=strlen(s);
Manacher(s,len);
int ans=0;
for(int i=0;i<2*len+2;i++)
ans=max(ans,Mp[i]−1);
printf("%d\n",ans);
}
return 0;
}
这个题的代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=2000000+10;
const ll mod=1e9+7;
const ull bas=100007;
ull p[maxn<<1],has[maxn<<1];
ll pw[maxn<<1],sum[maxn<<1];
const int MOD=4000007;
int first[maxn<<1],nxt[maxn<<1],cnt=0;
ull val[maxn<<1];
bool exist(ull now)
{
int u=now%MOD;
for(int i=first[u];i;i=nxt[i])
if(val[i]==now) return true;
nxt[++cnt]=first[u];
first[u]=cnt;
val[cnt]=now;
return false;
}
ull gethas(int l,int r)
{
return has[r]-has[l-1]*p[r-l+1];
}
ll solve(int l,int r)
{
ull tmp=gethas(l,r);
if(exist(tmp)) return 0;
ll ans=sum[r]-sum[l-1]*pw[(r-l+1+1)/2]%mod+mod;
if(ans>mod)
ans%=mod;
return ans;
}
char Ma[maxn<<1];
int Mp[maxn<<1];
ll Manacher(char s[],int len)
{
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++)
{
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
pw[0]=p[0]=1;
has[0]=sum[0]=0;
for(int i=1;i<=l;i++)
{
p[i]=p[i-1]*bas;
has[i]=has[i-1]*bas+Ma[i];
pw[i]=pw[i-1]*10%mod;
if(Ma[i]>='0'&&Ma[i]<='9')
sum[i]=(sum[i-1]*10+Ma[i]-'0')%mod;
else
sum[i]=sum[i-1];
}
ll ans=0;
int mx=0,id=0;
for(int i=0;i<l;i++)
{
if(Ma[i]!='#')
ans=(ans+solve(i,i))%mod;
Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]])
{
if(Ma[i+Mp[i]]!='#')
ans=(ans+solve(i-Mp[i],i+Mp[i]))%mod;
Mp[i]++;
}
if(i+Mp[i]>mx)
{
mx=i+Mp[i];
id=i;
}
}
return ans;
}
char s[maxn];
int main()
{
scanf("%s",s);
int len=strlen(s);
printf("%lld\n",Manacher(s,len));
return 0;
}