题解:P10694 [SNCPC2024] 双子序列
BuQiuRu4587 · · 题解
看完题,感觉这个子序列有点难直接做的,至少直接算出每一个区间的贡献估计是没有前途,所以我们考虑拆贡献。
乘法形式拆贡献有经典 trick,使用乘法分配律,发现对于一对子序列
这个形式已经足够 dp 了,具体来说,我们考虑枚举
考虑转移,这是相当简单的,
使用前缀和优化可以做到
最开始答案没取模罚了一发/fn。
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
string s,s1,s2;
int f[100005][21][21];
int sum[21][21];
int n,l1,l2;
void rtt(int x){
for(int i=0;i<=l1;i++){
for(int j=0;j<=l2;j++){
sum[i][j]+=f[x][i][j];
if(sum[i][j]>=mod) sum[i][j]-=mod;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>s>>s1>>s2;
n=s.size(),l1=s1.size(),l2=s2.size();
s='#'+s;
s1='#'+s1;
s2='#'+s2;
int ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=l1;j++){
for(int k=0;k<=l2;k++){
if(s1[j]!=s[i]&&s2[k]!=s[i]) continue;
if(s1[j]==s[i]){
f[i][j][k]+=sum[j-1][k]+(j==1&&k==0)*i;
if(f[i][j][k]>=mod) f[i][j][k]-=mod;
}
if(s2[k]==s[i]){
f[i][j][k]+=sum[j][k-1]+(j==0&&k==1)*i;
if(f[i][j][k]>=mod) f[i][j][k]-=mod;
}
if(s1[j]==s[i]&&s2[k]==s[i]){
f[i][j][k]+=sum[j-1][k-1]+(j==1&&k==1)*i;
if(f[i][j][k]>=mod) f[i][j][k]-=mod;
}
}
}
ans+=f[i][l1][l2]*(n-i+1)%mod;
rtt(i);
}
cout<<ans%mod;
}