[硫化铂]T3

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 rl+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,rlen+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} id1018,不说要处理极多的后缀自动机,每个串还是极长的,显然不大现实。
可我们发现,我们实际上只需要找到它们最小的 i i i使得 ∣ S i ∣ ⩾ ∣ S ∣ |S_i|\geqslant |S| SiS,那样的话,我们匹配的位置要么被 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| logSi个,每个都建出来算算就行。
由于我们的 ∣ 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;
}

谢谢!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值