题意:
两个串,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] > t[j]) 那么该贡献为:
前面匹配j-1的种类数*后面随便选len2-j个,即当前的贡献就为dp[i - 1][j - 1] * C[len1 - i][len2 - j]。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 3005; 5 const ll mod = 998244353 ; 6 char s[N],t[N]; 7 ll C[N][N]; 8 ll dp[N][N]; 9 int main() 10 { 11 //打表杨辉三角 12 C[0][0] = 1 ; 13 C[1][0] = C[1][1] = 1 ; 14 for(int i=2;i<=3000;i++){ 15 C[i][0] = 1 ; 16 for(int j=1;j<=i;j++){ 17 C[i][j] = C[i-1][j-1] + C[i-1][j] ; 18 if(C[i][j]>=mod) C[i][j] -= mod ; 19 } 20 } 21 22 int T,n,m; 23 for( scanf("%d",&T) ; T ; T-- ){ 24 scanf("%d%d",&n,&m); 25 scanf("%s%s",s+1,t+1); 26 27 for(int i=0;i<=n;i++){ 28 dp[i][0] = 1 ; 29 } 30 //计算长度相同时,某一位置比t的位置大,对答案的贡献 31 ll ans = 0 ; 32 for(int i=1;i<=n;i++){ 33 for(int j=1;j<=min(i,m);j++){ 34 dp[i][j] = dp[i-1][j] ; 35 if( s[i] == t[j] ){ 36 dp[i][j] = (dp[i][j] + dp[i-1][j-1]) % mod ; 37 } 38 else if( s[i] > t[j] ){ 39 ans = (ans + (ll)dp[i-1][j-1] * C[n-i][m-j]) %mod ; 40 } 41 } 42 } 43 //计算长度大于t串长度时,对答案的贡献 44 for(int i=1;i<=n;i++){ 45 if( s[i] =='0' ) continue ; 46 for(int j=m;j<=n-i;j++){ 47 ans = (ans + C[n-i][j])%mod ; 48 } 49 } 50 printf("%lld ",ans); 51 } 52 return 0; 53 }