//the code is from chenjh
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int mod=998244353;
int n,m;
LL k;
char s[5005],t[11];
int main(){
scanf("%lld %s %s",&k,s,t),n=strlen(s),m=strlen(t);
int ans=0;
for(int i=0;i<n;i++)for(int j=i+1;j<n;j++)
(ans+=s[i]==t[0]&&s[j]==t[1])>=mod&&(ans-=mod);
printf("%d\n",ans);
return 0;
}
测试点 4,5
和上一部分不同之处在于 k 的范围扩大到了 k \le 100,也就是说 k n \le 5 \times 10^5。
统计满足的二元组数量,只需要枚举一维,快速算另一维即可。
前缀和统计一下 T_0 的数量,遇到 T_1 相加一下即可,时间复杂度 O(k n)。
//the code is from chenjh
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int mod=998244353;
int n,m;
LL k;
char s[5005],t[11];
int main(){
scanf("%lld %s %s",&k,s,t),n=strlen(s),m=strlen(t);
int ans=0,w=0;
while(k--)for(int i=0;i<n;i++) s[i]==t[1]&&(ans+=w)>=mod&&(ans-=mod),w+=s[i]==t[0];
printf("%d\n",ans);
return 0;
}
测试点 6,7
根据测试点 3 的方式直接枚举判断即可,时间复杂度 O(n ^ {m}),代码过于简单就不放了。
测试点 8,9,10
各种数据范围都相比前面的有所加强,所以不能暴力枚举了,考虑动态规划。
状态设计
设 f_{i,j} 表示字符串 s 前 i 个字符中 T 前 j 个字符组成的字符串出现的子序列方案数。
//the code is from chenjh
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int mod=998244353;
int n,m;
LL k;
char s[5005],t[11];
int f[11];
int main(){
scanf("%lld %s %s",&k,s,t),n=strlen(s),m=strlen(t);
*f=1;
while(k--)for(int i=0;i<n;i++)for(int j=m;j>0;--j)s[i]==t[j-1]&&(f[j]+=f[j-1])>=mod&&(f[j]-=mod);
printf("%d\n",f[m]);
return 0;
}