【形式化题意】
给定一个正整数 和两个字符串 。
设字符串 为 个字符串 首尾相接得到的字符串,。
设答案集合 ,请求出 。
输入共 行。
第 行 个整数,表示 。
第 行 个字符串,表示 。
第 行 个字符串,表示 。
输出共 行 个整数,表示答案。
【样例 1 解释】
将 重复 次得到 。
答案集合 ,因此 。
【数据范围】
对于 的数据,,,,字符串 均由小写英文字母组成。
想到了做一个 ,但是一上来就把阶段丢掉了,导致把自己绕晕了,大概想的是定义 为:如果 的当前位置位在 中,那么选完了这一位以后对应的方案数 , 代表 中对应的第 个字符。转移的时候就统计前缀和就行,但这样的想法很容易被 掉,还是我太菜了,很显然的一个例子是 ,当我们枚举到 中某位是 时, 会从 进行转移,因此会多统计出来一部分。
重新定义 为考虑完 中前 个后,选完 串中第 个位置的方案数,那么转移方程也十分的明显了。
发现 的数据范围尤其的大,基本上要么就是推数学结论,要么就是矩阵加速递推,现在 都写出来了,这下不得不递推了。
和普通的矩阵加速不同(很大可能是我刷的题太少了),本题的 是带条件的,也就是说,在某一个循环内枚举的时候,有可能会有很多个不同的转移矩阵。
但最重要的地方在于,这些转移矩阵的出现是有规律的,如 一共有 个这样的循环,那么我们记每一个循环根据结合律得出的转移矩阵是 ,总的转移矩阵就是 。
最后在初始 矩阵右乘上一个 就好了。
注意 的初值应该赋为 ,不然答案为 了。
然后还有就是,由于每一个循环节内的子转移矩阵是不同的,所以累乘的方式应该根据 是左乘还是右乘转移矩阵有所变化,比如下面给出的代码是左乘转移矩阵,那么在预处理的时候也应该从左边乘进来,类似于一个栈的结构。
| #include<bits/stdc++.h> |
| #define int long long |
| using namespace std; |
| const int N=20; |
| struct Matrix |
| { |
| int n,m; |
| int a[N][N]; |
| Matrix() |
| { |
| memset(a,0,sizeof(a)); |
| } |
| void reset() |
| { |
| memset(a,0,sizeof(a)); |
| } |
| void print() |
| { |
| for(int i=0;i<=n;++i) |
| { |
| for(int j=0;j<=m;++j) |
| printf("%lld ",a[i][j]); |
| putchar('\n'); |
| } |
| } |
| }; |
| Matrix I(int n) |
| { |
| Matrix tmp; |
| tmp.n=tmp.m=n; |
| for(register int i=0;i<=n;++i)tmp.a[i][i]=1; |
| return tmp; |
| } |
| const int MOD=998244353; |
| Matrix operator *(Matrix a,Matrix b) |
| { |
| Matrix tmp; |
| tmp.n=a.n,tmp.m=b.m; |
| for(register int i=0;i<=a.n;++i) |
| for(register int j=0;j<=b.m;j++) |
| for(register int k=0;k<=a.m;++k) |
| tmp.a[i][j]+=a.a[i][k]*b.a[k][j]%MOD,tmp.a[i][j]%=MOD; |
| return tmp; |
| } |
| inline Matrix power(Matrix a,int b) |
| { |
| Matrix ans=I(a.n); |
| while(b) |
| { |
| if(b&1)ans=ans*a; |
| a=a*a; |
| b>>=1; |
| } |
| return ans; |
| } |
| int k,n; |
| char s[50000],t[100]; |
| Matrix Ans,sup; |
| vector<int> rec[200]; |
| inline void pre() |
| { |
| cin>>k; |
| cin>>s>>t; |
| n=strlen(t); |
| for(int i=0;i<n;++i)rec[t[i]].push_back(i+1); |
| sup=I(n); |
| Matrix tmp; |
| for(register int i=0;i<strlen(s);++i) |
| { |
| tmp=I(n); |
| for(int j=0;j<rec[s[i]].size();++j) |
| { |
| int pos=rec[s[i]][j]; |
| tmp.a[pos][pos-1]=1; |
| } |
| sup=tmp*sup; |
| } |
| Ans.n=n,Ans.m=1,Ans.a[0][1]=1; |
| } |
| signed main() |
| { |
| pre(); |
| Ans=power(sup,k)*Ans; |
| cout<<Ans.a[n][1]; |
| return 0; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效