T3
题目概述
题解
这名字也太草了。
首先,字符串同构的定义是,二者是循环同构的。
我们先考虑对于一个不是很长的给定串
T
T
T,我们查询它里面与
S
S
S循环同构的子串有多少。
既然是循环同构,那么我们显然可以去考虑将所有循环同构的部分都放过去查一查。
但如果所有循环串去查的话那不就达到
M
2
M^2
M2了吗,没事,我们可以的循环同构一定可以被看成
一
段
前
缀
+
一
段
后
缀
一段前缀+一段后缀
一段前缀+一段后缀的形式,我们可以考虑对于前后缀各做一个KMP,然后拼起来看每个位置能否填满。
但事实上这样是不可能过的,毕竟每次询问都会达到
O
(
∣
S
∣
+
∣
T
∣
)
O\left(|S|+|T|\right)
O(∣S∣+∣T∣),显然不可能过。
但我们完全可以优化这个复杂度嘛。
我们发现前后缀做
K
M
P
KMP
KMP也太麻烦了,我们可以转化一下,将两个
S
S
S串拼在一起,那么里面的任意一个长度为
∣
S
∣
|S|
∣S∣的子串,都可以表示原
S
S
S串的一个循环同构。
于是,我们查询的就成了我们
S
S
SS
SS串中哪些位置对应的前缀的长度至少为
∣
S
∣
|S|
∣S∣的后缀在
∣
T
∣
|T|
∣T∣中出现。
我们不妨将我们的
T
T
T串建一个后缀自动机,查询串的时候就直接在串上用双指针跑,走
c
h
i
l
d
r
e
n
children
children的边就相当于让我们的
r
+
+
r++
r++,而跳父亲边回退也就是让我们的
l
+
+
l++
l++。
由于我们的父亲位置的
l
e
n
len
len记录的是该位置的最长公共串长度,而有可能我们的
r
−
l
+
1
r-l+1
r−l+1完全小于该节点上的
l
e
n
len
len,也就是说我们匹配的不是该节点的最长串,只是一个前缀的子串。但没关系,我们向父亲跳不过是让我们的
l
,
r
l,r
l,r间的距离不超过
l
e
n
len
len,让
l
=
max
(
l
,
r
−
l
e
n
+
1
)
l=\max(l,r-len+1)
l=max(l,r−len+1)。
我们就找到能使得
l
,
r
l,r
l,r不小于
∣
S
∣
|S|
∣S∣的最高的点,如果有的话,我们就能够知道这种循环同构在
T
T
T上有多少一样的子串了。
当然,我们的两个
S
S
S拼在一起不一定组成的每个长为
∣
S
∣
|S|
∣S∣的子串都是不同的。这个只需要我们预先用
K
M
P
KMP
KMP处理一下,如果某个点的
f
a
i
l
fail
fail不小于
∣
S
∣
|S|
∣S∣,就不算它的贡献就行了。
这样预处理每个后缀自动机,我们的查询就是
O
(
∣
S
∣
)
O\left(|S|\right)
O(∣S∣)的了。
但是我们的
i
d
⩽
1
0
18
id\leqslant 10^{18}
id⩽1018,不说要处理极多的后缀自动机,每个串还是极长的,显然不大现实。
可我们发现,我们实际上只需要找到它们最小的
i
i
i使得
∣
S
i
∣
⩾
∣
S
∣
|S_i|\geqslant |S|
∣Si∣⩾∣S∣,那样的话,我们匹配的位置要么被
S
i
S_i
Si或者
S
i
+
1
S_{i+1}
Si+1完全包含,要么就是在它们之间。
也就是说,我们的
S
i
d
S_{id}
Sid肯定是由许多个
S
i
S_i
Si和
S
i
+
1
S_{i+1}
Si+1拼接而成,我们只需要算一下
S
i
,
S
i
+
1
S_i,S_{i+1}
Si,Si+1内部,
S
i
S
i
+
1
,
S
i
+
1
S
i
+
1
,
S
i
+
1
S
i
S_iS_{i+1},S_{i+1}S_{i+1},S_{i+1}S_{i}
SiSi+1,Si+1Si+1,Si+1Si拼接处的贡献就行。
然后之后就只用用矩阵算出这
5
5
5种贡献每个的系数,加起来就可以了。
由于我们的
∣
S
i
∣
|S_i|
∣Si∣的增大是斐波拉契形式,也就是指数级的,也就是说,我们的后缀自动机只会有
log
∣
S
i
∣
\log |S_i|
log∣Si∣个,每个都建出来算算就行。
由于我们的
∣
M
∣
|M|
∣M∣达到了
1
0
6
10^6
106级别,空间可能有点大,建议离线下来,建一个算一个。
记矩阵长度为 d d d,时间复杂度 O ( n + M + q d 3 log i d ) O\left(n+M+qd^3\log id\right) O(n+M+qd3logid)。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000005
#define MAXM 8000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
typedef long double Ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int mod=1e5+7;
const int inv2=499122177;
const int inv3=332748118;
const double jzm=0.999;
const int zero=2000;
const int n1=100;
const int lim=100000;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-8;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
char str[MAXN];bool vis[26];LL id[MAXN];
int s[2][MAXM],st[MAXN],ed[MAXN],dp[MAXN][5],ip[MAXN];
int len[2],idx,f[55],q,totf,sta[MAXM],stak;
vector<int>vec[55];
struct matrix{
int c[15][15];matrix(){}
void clear(){for(int i=0;i<14;i++)for(int j=0;j<14;j++)c[i][j]=0;}
matrix operator * (const matrix &rhs)const{
matrix res;res.clear();
for(int i=0;i<14;i++)
for(int k=0;k<14;k++)if(c[i][k])
for(int j=0;j<14;j++)
Add(res.c[i][j],1ll*c[i][k]*rhs.c[k][j]%mo,mo);
return res;
}
}P[70],A;
struct ming{
int ch[26],len,fa,cnt,deg;
ming(){len=fa=cnt=deg=0;for(int i=0;i<26;i++)ch[i]=0;}
};
class Suffix_Automaton{
private:
ming tr[MAXM];int tot,las,t[MAXM];queue<int>qp;
public:
void init(){las=++tot;}
void extend(int c){
int p=las,u=las=++tot;tr[u].len=tr[p].len+1;tr[u].cnt=1;
for(;p&&!tr[p].ch[c];p=tr[p].fa)tr[p].ch[c]=u;
if(!p){tr[u].fa=1;return ;}int q=tr[p].ch[c];
if(tr[q].len==tr[p].len+1)tr[u].fa=q;
else{
int x=++tot;tr[x].fa=tr[q].fa;tr[x].len=tr[p].len+1;
for(int i=0;i<26;i++)tr[x].ch[i]=tr[q].ch[i];
for(;p&&tr[p].ch[c]==q;p=tr[p].fa)tr[p].ch[c]=x;
tr[q].fa=tr[u].fa=x;
}
}
void solve(){
for(int i=1;i<=tot;i++)if(tr[i].fa)tr[tr[i].fa].deg++;
for(int i=1;i<=tot;i++)if(!tr[i].deg)qp.push(i);
while(!qp.empty()){
int u=qp.front();qp.pop();
if(tr[u].fa){
tr[tr[u].fa].deg--;tr[tr[u].fa].cnt+=tr[u].cnt;
if(!tr[tr[u].fa].deg)qp.push(tr[u].fa);
}
}
}
int query(int *A,int n){
int now=1,l=1,res=0;t[1]=0;
for(int i=2;i<=n+n;i++){
int nw=t[i-1];while(nw&&A[nw+1]!=A[i])nw=t[nw];
if(A[nw+1]==A[i])t[i]=nw+1;else t[i]=0;
}
for(int r=1;r<=n+n;r++){
while(now&&!tr[now].ch[A[r]])now=tr[now].fa,l=max(l,r-tr[now].len);
if(tr[now].ch[A[r]])now=tr[now].ch[A[r]];else now=1,l=r+1;
while(r-l+1>=n&&tr[tr[now].fa].len>=n)
now=tr[now].fa,l=max(l,r-tr[now].len+1);
if(r-l+1>=n&&t[r]<n)Add(res,tr[now].cnt,mo);
}
return res;
}
void clear(){for(int i=1;i<=tot;i++)tr[i]=ming();tot=0;}
}T;
signed main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%s\n",str+1);len[0]=(int)strlen(str+1);
for(int i=1;i<=len[0];i++)s[0][i]=str[i]-'a',str[i]=0;
scanf("%s\n",str+1);len[1]=(int)strlen(str+1);
for(int i=1;i<=len[1];i++)s[1][i]=str[i]-'a',str[i]=0;
f[1]=len[0];f[2]=len[1];totf=2;read(q);int maxx=0;
while(f[totf-1]<1e6)totf++,f[totf]=f[totf-1]+f[totf-2];
for(int i=1;i<=q;i++){
st[i]=ed[i-1]+1;scanf("%lld %s",&id[i],str+st[i]);
int lenn=(int)strlen(str+st[i]);ed[i]=st[i]+lenn-1;
for(int j=1;j<=totf;j++)if(f[j]>=lenn){vec[j].pb(i);ip[i]=j;break;}
}
for(int i=1;i<=q;i++)maxx=max(maxx,ip[i]);T.init();
for(int i=1;i<=len[0];i++)T.extend(s[0][i]);T.solve();
for(int i=1;i<=maxx;i++){
int siz=vec[i].size();
for(int j=0;j<siz;j++){
int x=vec[i][j],lenn=ed[x]-st[x]+1;stak=0;
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
dp[x][0]=T.query(sta,lenn);
}
T.clear();T.init();
for(int j=1;j<=len[0];j++)T.extend(s[0][j]);
for(int j=1;j<=len[1];j++)T.extend(s[1][j]);
T.solve();
for(int j=0;j<siz;j++){
int x=vec[i][j],lenn=ed[x]-st[x]+1;stak=0;
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
dp[x][1]=T.query(sta,lenn);
}
T.clear();T.init();
for(int j=1;j<=len[1];j++)T.extend(s[1][j]);
for(int j=1;j<=len[1];j++)T.extend(s[1][j]);
T.solve();
for(int j=0;j<siz;j++){
int x=vec[i][j],lenn=ed[x]-st[x]+1;stak=0;
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
dp[x][2]=T.query(sta,lenn);
}
T.clear();T.init();
for(int j=1;j<=len[1];j++)T.extend(s[1][j]);
for(int j=1;j<=len[0];j++)T.extend(s[0][j]);
T.solve();
for(int j=0;j<siz;j++){
int x=vec[i][j],lenn=ed[x]-st[x]+1;stak=0;
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
dp[x][3]=T.query(sta,lenn);
}
T.clear();T.init();
for(int j=1;j<=len[1];j++)T.extend(s[1][j]);
T.solve();
for(int j=0;j<siz;j++){
int x=vec[i][j],lenn=ed[x]-st[x]+1;stak=0;
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
for(int k=1;k<=lenn;k++)sta[++stak]=str[k+st[x]-1]-'a';
dp[x][4]=T.query(sta,lenn);
}
if(i==maxx)break;
stak=len[0];len[0]=len[1];//puts("fifth end");
for(int j=1;j<=stak;j++)sta[j]=s[0][j];
for(int j=1;j<=len[1];j++)s[0][j]=s[1][j];
for(int j=1;j<=stak;j++)s[1][++len[1]]=sta[j];
}
P[0].clear();
for(int i=0;i<7;i++)P[0].c[i+7][i]=1;
for(int i=0;i<7;i++)P[0].c[i][i+7]=1;
for(int i=0;i<5;i++)P[0].c[i+7][i+7]=1;
P[0].c[12][8]=P[0].c[13][9]=1;
for(int i=1;i<=60;i++)P[i]=P[i-1]*P[i-1];
for(int i=1;i<=q;i++){
if(id[i]<ip[i]){puts("0");continue;}
if(id[i]==ip[i]){printf("%d\n",dp[i][0]);continue;}
if(id[i]==ip[i]+1){printf("%d\n",dp[i][4]);continue;}
Add(dp[i][1],mo-add(dp[i][0],dp[i][4],mo),mo);
Add(dp[i][2],mo-add(dp[i][4],dp[i][4],mo),mo);
Add(dp[i][3],mo-add(dp[i][4],dp[i][0],mo),mo);
A.clear();A.c[0][4]=A.c[0][6]=A.c[0][7]=A.c[0][10]=A.c[0][11]=A.c[0][12]=1;
LL ti=id[i]-ip[i]-1;int ans=0;
for(int j=0;j<=60;j++)if((ti>>j)&1LL)A=A*P[j];
for(int j=0;j<5;j++)Add(ans,1ll*dp[i][j]*A.c[0][j]%mo,mo);
printf("%d\n",ans);
}
return 0;
}