【动态规划】subsequence 1

题意:

两个串,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 }
View Code
 
 
 
原文地址:https://www.cnblogs.com/Osea/p/11297874.html