-
题意:两个字符串s和t,求s的子序列中大于t的个数
-
思路:1,当s的子序列长度小于t的长度时肯定不满足。
2, 当s的子序列长度等于t的长度时,可用dp求解:
从后往前dp,dp[i][j]表示长度为长度为i的s长度为j的t满足条件的个数,
分三种情况:
(1),当s[i]<t[j],则当前的字母不可取,在之后i-1 个字母中选取j个,即:dp[i][j]=dp[i-1][j]
(2),当s[i]=t[i],如果取当前字母,则考虑之后的i-1个s和j-1个t的关系,如果不取当前字母,则在i-1个s取j个
即:dp[i][j]=dp[i-1][j-1]+dp[i-1][j]
(3),当s[i]>[j],如果取当前字母,则剩下的j-1个字母可以在i-1中任意取,如果不取当前字母,则考虑i-1和j的关系
即:dp[i][j]= c[i-1][j-1] + dp[i-1][j];
3, 当s的子序列长度等于t的长度时,用组合数求解,预处理组合数
c[i][j]=c[i-1][j-1]+c[i-1][j]; -
代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
char s[3005];
char t[3005];
int c[3005][3005];
int dp[3005][3005];
void init(){
int i,j;
for(i=0;i<=3000;i++){
c[i][i]=1;
c[i][0]=1;
for(j=1;j<i;j++){
c[i][j]=c[i-1][j]+c[i-1][j-1];
c[i][j]=c[i][j]%998244353;
}
}
}
int main(){
int k;
init();
scanf("%d",&k);
while(k--){
int n,m,x,y;
scanf("%d %d",&n,&m);
scanf("%s %s",s+1,t+1);
int i,j;
for(i=0;i<=n;i++){
for(j=0;j<=m;j++){
dp[i][j]=0;
}
}
for(i=1,x=n;i<=n;i++,x--){
for(j=1,y=m;j<=min(i,m);j++,y--){
if(s[x]<t[y]){
dp[i][j]=dp[i-1][j];
}
else if(s[x]>t[y]) {
dp[i][j]=( c[i-1][j-1] + dp[i-1][j] )%998244353;
}
else if(s[x]==t[y]){
dp[i][j]=( dp[i-1][j-1] + dp[i-1][j] )%998244353;
}
}
}
int sum=dp[n][m];
for(i=1;i<=n-m;i++){
for(j=m;j<=n-i;j++)
if(s[i]!='0'){
sum=sum+c[n-i][j];
sum=sum%998244353;
}
}
printf("%d\n" ,sum);
}
}