题意:给你两个字符串都是数字,让你求第一个字符串的子序列中大于第二个字符串的个数。
思路:dp[i][j] 表示 str1的前i个,匹配 str2的前 j 个的种类数,那么 if(s[i] == t[j]) dp[i][j] = dp[i -1][j] + dp[i - 1][j - 1]; else dp[i][j] = dp[i - 1][j]; 对于长度大于 t 的没有前导0的都符合,那么就看长度等于t的就可以了,当匹配到 i, j 的时候,if(s[i] > s[j]) 那么该贡献为:前面匹配j-1的种类数*后面随便选len2-j个,即当前的贡献就为dp[i - 1][j - 1] * C[len1 - i][len2 - j]。
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<map> #include<vector> #include<queue> #include<cmath> #define ll long long using namespace std; const int mod=998244353; char str1[30001],str2[30001]; int dp[3010][3011]; int C[3010][3010]; int main() { int t; C[0][0] = C[1][0] = C[1][1] = 1; for(int i = 2; i <= 3000; i++) { C[i][0] = 1; for(int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod; } scanf("%d",&t); while(t--) { int n,m; long long sum=0; scanf("%d%d",&n,&m); scanf("%s%s",str1+1,str2+1); int len1=strlen(str1+1); int len2=strlen(str2+1); for(int i=0;i<=len1;i++) dp[i][0]=1; for(int i=1;i<=len1;i++) { for(int j=1;j<=min(len2,i);j++) { dp[i][j]=dp[i-1][j]; if(str1[i]==str2[j]) dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod; if(str1[i]>str2[j]) { sum=(sum+(ll)dp[i-1][j-1]*C[len1-i][len2-j])%mod; } } } for(int i=1;i<=len1;i++) { if(str1[i]=='0') continue; for(int j=len2;j<=len1-i;j++) sum=(sum+C[len1-i][j])%mod; } printf("%lld ",sum); } }