题意:给你一个字符串,q次查询,每次查询会将字符串中的一个字符修改为#,求在新串中可以选出几种长度不同的前后缀,使得前后缀相同
分析:对于长度为n的串,#在pos位置时,只需对长度小于等于min(pos-1,n-pos)的前后缀查询即可
q在1e6 故要先预处理主串看看有哪些长度的前后缀是相同的 再O(1)查询
字符串哈希做法:
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
const int maxn=1e6+5;
const int p=131;
ull hs[maxn];//字符串哈希前缀和
ull bin[maxn];//进制
char c[maxn];
int ans[maxn];
int n;
void gethash()//预处理主串
{
bin[0]=1;
for(int i=1;i<=n;i++)
{
hs[i]=hs[i-1]*p+c[i];
bin[i]=bin[i-1]*p;
}
}
ull getsub(int l,int r)//子串哈希值
{
return hs[r]-hs[l-1]*bin[r-l+1];
}
int main()
{
scanf("%s",c+1);
n=strlen(c+1);
gethash();
for(int i=1;i<=n/2;i++)
{
if(getsub(1,i)==getsub(n-i+1,n))
{
ans[i]=ans[i-1]+1;//前缀长度为i时能取到的最大方案数
}
else ans[i]=ans[i-1];
}
int m;
cin>>m;
while(m--)
{
int pos;
scanf("%d",&pos);//1e6
pos=min(pos-1,n-pos);
printf("%d\n",ans[pos]);
}
}
next数组做法:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
char s[maxn];
int n;
int nxt[maxn];
int ans[maxn];
void getnext()
{
int j=0;
for(int i=2;i<=n;i++)
{
while(j&&s[i]!=s[j+1]) j=nxt[j];
if(s[i]==s[j+1]) j++;
nxt[i]=j;
}
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
getnext();
int p=nxt[n];
while(p) ans[p]++,p=nxt[p];
for(int i=1;i<=n/2;i++) ans[i]+=ans[i-1];
int m;
cin>>m;
while(m--)
{
int pos;
scanf("%d",&pos);
pos=min(pos-1,n-pos);
printf("%d\n",ans[pos]);
}
}