题目链接:https://ac.nowcoder.com/acm/contest/885/G
题意:两个串,s t,求s的所有子串中大于 t 的数目
题解:dp[i][j] 表示 s的前i个,匹配 t 的前 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 <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 3010;
int n, m;
int dp[N][N];
int C[N][N];
char s[N], t[N];
int main() {
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;
}
int T;
int len1, len2;
ll ans;
scanf("%d", &T);
while(T--) {
scanf("%d %d", &n, &m);
scanf("%s %s", s + 1, t + 1);
len1 = strlen(s + 1);
len2 = strlen(t + 1);
for(int i = 0; i <= len1; i++)
dp[i][0] = 1;
ans = 0;
for(int i = 1; i <= len1; i++)
for(int j = 1; j <= min(len2, i); j++) {
dp[i][j] = dp[i - 1][j];
if(s[i] == t[j]) dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % mod;
if(s[i] > t[j] ) {
ans = (ans + (ll)dp[i - 1][j - 1] * C[len1 - i][len2 - j]) % mod;
}
}
for(int i = 1; i <= len1; i++) {
if(s[i] == '0') continue;
for(int j = len2; j <= len1 - i; j++)
ans = (ans + C[len1 - i][j]) % mod;
}
printf("%lld\n", ans);
}
return 0;
}