Count the string
题目
求一个字符串的所有子串的匹配个数和
思路
预处理出next数组,可知每个next数组记录该串的最大前缀的长度(数值上等价于下标)。那么对于某一个长位n的子串s,除了 它本身和模板串匹配外,还有它的最大相同后缀。
那么, ans = 本身的一个 + 最大相同后缀
关于不重不漏,由于答案的第一部分的头部都是模板串的第一个字符,对不同长度一定不同,对第二部分,末尾字符不会相同,同样不会重复
- 预处理nxt数组
- 取出一个前缀串,去检查它的[最小相同后缀~最大相同后缀]个数,显然每一个不同后缀提供一个
- 加上这个前缀串提供的。
- 重复 2, 3步
模拟加深理解
s nxt ans
abab 2 ans=1
ab 0 ans=1
0 ans=2
aba 1 ans=3
a 0 ans=3
0 ans=4
ab 0 ans=4
0 ans=5
a 0 ans=5
0 ans=6
ans = 6
ans = 本身的一个 + 后缀匹配上的一个
abab 1 + 1
aba 1 + 1
ab 1 + 0
a 1 + 0
AC代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 10 + 2e5, mod = 10007;
int n;
char str[N];
int nxt[N];
void solve()
{
cin >> n >> str + 1;
nxt[1]=0;
for(int i=2,j=0;i<=n;i++)// 预处理
{
while(j>0&&str[i]!=str[j+1])j=nxt[j];
if(str[j+1]==str[i])j++;
nxt[i] = j;
}
int ans=0;
for(int i=1;i<=n;i++)
{
int tmp=nxt[i];
while(tmp)// 遍历该前缀的所有可匹配后缀
{
ans++;
ans%=mod;
tmp=nxt[tmp];
}
ans++;// 补上前缀提供的
}
cout << ans%mod << endl;
}
signed main()
{
ios::sync_with_stdio();
cin.tie();
cout.tie();
int T;
cin >> T;
int T1 = clock();
while (T--)
solve();
int T2 = clock();
//cerr<<endl<<" Time : "<< T2-T1 <<"ms."<<endl;
return 0;
}