题目:BZOJ3670.
题目大意:给定一个长度为
n
n
n的字符串,求这个字符串每一个前缀
S
[
1..
i
]
S[1..i]
S[1..i]的既是前缀又是后缀且这两个前后缀不能重叠的子串的数量
n
u
m
[
i
]
num[i]
num[i],并输出所有
(
n
u
m
[
i
]
+
1
)
(num[i]+1)
(num[i]+1)的乘积.
1
≤
n
≤
1
0
6
1\leq n\leq 10^6
1≤n≤106,数据组数
≤
5
\leq 5
≤5.
这道题是道语文题,题面又臭又长而且 n u m [ i ] num[i] num[i]的定义是数量不是最长长度,在题面理解上直接是被坑许久啊…
首先考虑没有前后缀不重叠这个条件的情况下该如何计数,考虑对于一个前缀 S [ 1.. i ] S[1..i] S[1..i],它既是前缀又是后缀的子串其实就只包括 S [ 1.. i ] , s [ 1.. n e x t [ i ] ] , S [ 1.. n e x t [ n e x t [ i ] ] ] , . . . S[1..i],s[1..next[i]],S[1..next[next[i]]],... S[1..i],s[1..next[i]],S[1..next[next[i]]],...那么数量也就是这样迭代下去可以进行的数量.
所以我们考虑记录 c n t [ i ] cnt[i] cnt[i]表示前缀 S [ 1.. i ] S[1..i] S[1..i]既是前缀又是后缀的子串数量,那么很明显 c n t [ i ] = 1 + c n t [ n e x t [ i ] ] cnt[i]=1+cnt[next[i]] cnt[i]=1+cnt[next[i]].
考虑有了前后缀不重叠的限制后的计算,也就是 n u m num num数组的计算,我们可以发现只需要计算出每一个前缀的最长的既是前缀又是后缀且前后缀不重叠的字串长度 n e x t 2 [ i ] next2[i] next2[i],我们就可以计算出 n u m [ i ] = c n t [ n e x t 2 [ i ] ] num[i]=cnt[next2[i]] num[i]=cnt[next2[i]].
发现那个 n e x t 2 next2 next2数组计算其实可以仿照 n e x t next next数组的计算,只是要在 n e x t next next计算的基础上多加一个条件 n e x t 2 [ i ] ∗ 2 < = i next2[i]*2<=i next2[i]∗2<=i就可以了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000000;
const LL mod=1000000007;
char a[N+9];
int n,nxt[N+9],nxt2[N+9];
LL ans,cnt[N+9];
Abigail into(){
scanf("%s",a+1);
n=strlen(a+1);
}
Abigail work(){
ans=1LL;
int j=0,j2=0;
nxt[1]=0;nxt2[1]=0;cnt[1]=1;
for (int i=2;i<=n;++i){
while (a[i]^a[j+1]&&j>0) j=nxt[j];
if (a[j+1]==a[i]) ++j;
nxt[i]=j;
while (a[i]^a[j2+1]&&j2>0) j2=nxt[j2];
if (a[j2+1]==a[i]) ++j2;
while (j2<<1>i) j2=nxt[j2];
nxt2[i]=j2;
cnt[i]=1+cnt[nxt[i]];
ans=ans*(cnt[nxt2[i]]+1)%mod;
}
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while (T--){
into();
work();
outo();
}
return 0;
}
本文详细解析了BZOJ3670题目,介绍了如何计算字符串前缀中既是前缀又是后缀的子串数量,并分享了一种算法实现思路。通过计算next数组和next2数组,有效解决了前后缀不重叠的问题。
&spm=1001.2101.3001.5002&articleId=87895388&d=1&t=3&u=9b5990ff19b34060ab668b404895b5c9)
956

被折叠的 条评论
为什么被折叠?



