题面:
众所周知,人类的本质是复读机。
有时候,小华会得到某个字符串S 。这时他会把S不断重复不断重复连成一个无限长的串kokodayo。比如说,小华现在得到一个串 ,他会一直复读,那么形成的字符串就是:
同样众所周知的是,发送消息的字长是有限制的。如果要发送的串超过了长度限制,那么就只会发送这个串的一个前缀。比如说对于上述无限长的字符串,若长度限制是13 ,那么实际发出去的字符串是 kokodayokokod 。
现在小华发出去了一个字符串T,但他不能确定他复读的字符串是什么了。他唯一知道的是,他复读的字符串,一定是m个字符串中的一个。他希望知道,在这m个字符串中,有多少个字符串可能是他复读后发送出去的呢?
输入:
第一行输入一个字符n,表示发送消息的长度限制。
第二行输入一个长度为n的字符串T,表示小华发送的消息。
第三行输入一个数m。表示字符串个数。
接下来m行,每行输入一个字符串S。
输出:
输出一行一个整数,表示m个串中经过复读并发出后能够形成T的串个数。
样例输入 :
9 abaabaaba 3 aba ab abaaba
样例输出:
2
约束条件:
对于 100% 的数据,1≤ n, m ≤ 10^6,1 ≤ |S| ≤ n, |S| ≤ 10^7 。
题解:
既然题目是要求复读串,显而易见是字符串压缩的问题。
这里,首先抛出一个结论:对于一个长度为 n 的字符串 S ,它的最短的“压缩”表示 t,(即我们希望寻找一个最短的字符串 ,使得 S 可以被 t 的一份或多份拷贝的拼接表示),t 的长度为 n-p[n] 。其中, p[n] 是指 S 下标 n 处的前缀函数。
因此,我们只需要求出 S 和 T 的最短“压缩”表示,然后比较看是否满足条件即可。
关于“前缀函数”的定义和“字符串压缩”结论的证明,参考这里有更加严谨的解释,本文只作解题思路,不再赘述。
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define endl '\n'
const int N=1e6+10;
char s[N],t[N];
int nxt[N],n,T,ans;
void getNxt(char p[N])
{
// 获取字符串各下标对应的前缀函数
int m=strlen(p+1);
int j=0;
nxt[1]=0;
for(int i=2;i<=m;i++)
{
while(j>0&&p[j+1]!=p[i]) j=nxt[j];
if(p[j+1]==p[i]) j++;
nxt[i]=j;
}
}
signed main()
{
cin>>n;
scanf("%s",s+1);
int mainlen=strlen(s+1);
getNxt(s);
// 根据结论,k 即是字符串 s 最短的“压缩”表示的长度
int k=mainlen-nxt[mainlen];
cin>>T;
while(T--)
{
scanf("%s",t+1);
int len=strlen(t+1);
if(len<mainlen)
{
if(len>k&&(len%k==0))
{
// 显然,t 的长度要能被 k 整除,才有可能是复读串
getNxt(t);
// 根据结论,tark 即是字符串 t 最短的“压缩”表示
int tark=len-nxt[len];
// 不仅 tark == k,而且两字符串的真前缀还得一一对应,t 才是复读串
if(tark==k)
{
int f=0;
for(int i=1;i<=tark;i++)
{
if(t[i]!=s[i])
{
f=1;
break;
}
}
if(!f) ans++;
}
}
else if(len==k)
{
// 如果字符串 t 和 s 最短的“压缩”表示一样长,那就暴力匹配
int f=0;
for(int i=1;i<=len;i++)
{
if(t[i]!=s[i])
{
f=1;
break;
}
}
if(!f) ans++;
}
}
else if(len==mainlen)
{
// 如果字符串 s 和字符串 t 一样长,那自然也是暴力匹配
int f=0;
for(int i=1;i<=mainlen;i++)
{
if(t[i]!=s[i])
{
f=1;
break;
}
}
if(!f) ans++;
}
}
cout<<ans;
return 0;
}
/**************************************************************
Problem: 16214
User: 2021UPC016
Language: C++
Result: 正确
Time:943 ms
Memory:7884 kb
****************************************************************/