学长学姐慈悲为怀
题意:给定一个字符串T,再给出若干个字符串S,对于每个S,找出其与T循环同构的字串个数。
题解:首先要弄清楚循环同构,循环同构就是将字符串T看成首尾相连的环,若T为"ababab",则对应的环如下图所示:
将环状T转化为链状Q,则Q=“abababababa”。即将T中的每个点都作为一次起点,形成一个长度为6的字符串。那么问题就转化为串S中有多少个子串可以作为串Q中长度为|T|的子串。然后利用字符串哈希将串S和Q哈希成整数,将Q的每个长度为|T|的子串哈希值存入数组,再将数组从小到大排序,为后面二分查找做准备。最后统计每个S中与T循环同构的字符串个数并输出。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define ull unsigned long long
const int N = 1e6+10;
const int P = 13331; // 字符串哈希时的进制数
ull h[2][N*2], p[N*2];
ull aT[N*2];
char T[N], S[N];
int n;
void hs(char *str, int len, int num)
{
p[0] = 1;
for(int i = 1;i <= len;i ++)
{
p[i] = p[i-1] * P;
h[num][i] = h[num][i-1] * P + str[i];
}
}
void init()
{
scanf("%s", T+1); // 从下标1开始
int lenT = strlen(T+1);
char Q[N*2];
for(int i = 1;i <= lenT;i ++) // 将T数组复制给Q数组
Q[i] = T[i];
for(int i = 1;i < lenT;i ++) // 环拆成链
Q[i+lenT] = T[i];
int lenQ = strlen(Q+1);
hs(Q, lenQ, 0);
for(int i = 0;i < lenT;i ++)
aT[i] = h[0][lenT+i] - h[0][i]*p[lenT]; // T中的环存入数组
sort(aT, aT+lenT);
}
void solve()
{
scanf("%s", S+1);
int lenT = strlen(T+1); // T环的长度
int lenS = strlen(S+1);
hs(S, lenS, 1);
int cnt = 0;
for(int i = 1, j = i+lenT-1;j <= lenS;i ++, j ++)
{
ull pre = h[1][j] - h[1][i-1]*p[j-i+1];
int idx = lower_bound(aT, aT+lenT, pre) - aT;
if(idx < lenT && aT[idx] == pre)
cnt ++;
}
printf("%d", cnt);
}
int main()
{
init();
scanf("%d", &n);
while(n --)
{
solve();
if(n) printf("\n");
}
return 0;
}
2021/11/06