题意:给长度为\(n\), \(m\)的字符串\(s\), \(t\), 字符串由0~9的数字组成,问在十进制意义下\(s\)中比\(t\)串大的子序列个数。c++
\(m\leq n \leq{3000}\).spa
题解:考虑两种不一样状况:子序列长度等于\(t\)串以及子序列长度大于\(t\)串。用\(len[i][j]\)维护\(s\)串中第\(i\)位之前长度为\(j\)的合法串(无前导零)个数,那么长度大于\(t\)串的个数为\(\sum_{i=m+1}^{n} len[n][i]\).code
用\(dp1[i][j]\)维护\(s\)串中第\(i\)位之前长度为\(j\)且严格大于\(t\)串中前\(j\)位的子序列个数, \(dp2[i][j]\)维护\(s\)串中第\(i\)位之前长度为\(j\)且大于等于\(t\)串前\(j\)位的子序列个数,很容易由\(s[i]\)和\(t[j]\)的大小关系得出一系列转移方程。 因而长度等于\(t\)串的个数为\(dp1[n][m]\).ci
代码:字符串
#include <bits/stdc++.h> using namespace std; const int mod = 998244353; char a[3005], b[3005]; int n, m; int dp1[3005][3005], len[3005][3005], dp2[3005][3005]; int main() { int T; cin >> T; while(T--) { scanf("%d%d", &n, &m); int ans1 = 0, ans2 = 0; int maxx = max(n, m); for(int i = 0; i <= maxx + 2; i++) for(int j = 0; j <= maxx + 2; j++) dp1[i][j] = dp2[i][j] = 0, len[i][j] = 0; scanf("%s%s", a + 1, b + 1); dp1[0][0] = 0; dp2[0][0] = 1; len[0][0] = 1; for(int i = 1; i <= n; i++) { len[i][0] = 1; for(int j = 1; j <= i; j++) len[i][j] = (len[i - 1][j - 1] + len[i - 1][j]) % mod; if(a[i] == '0') len[i][1] = len[i - 1][1]; dp2[i][0] = 1; for(int j = 1; j <= i; j++) { dp1[i][j] = dp1[i - 1][j]; dp2[i][j] = dp2[i - 1][j]; if(a[i] <= b[j]) { dp1[i][j] = (dp1[i][j] + dp1[i - 1][j - 1]) % mod; if(a[i] == b[j]) dp2[i][j] = (dp2[i][j] + dp2[i - 1][j - 1]) % mod; else dp2[i][j] = (dp2[i][j] + dp1[i - 1][j - 1]) % mod; } if(a[i] > b[j]) { dp1[i][j] = (dp1[i][j] + dp2[i - 1][j - 1]) % mod; dp2[i][j] = (dp2[i][j] + dp2[i - 1][j - 1]) % mod; } //dp2[i][j] += dp1[i - 1][j - 1]; } } for(int i = m + 1; i <= n; i++) ans1 = (ans1 + len[n][i]) % mod; ans2 = dp1[n][m]; int ans = (ans1 + ans2) % mod; printf("%d\n", ans); } return 0; }