zoukankan      html  css  js  c++  java
  • 2019牛客多校第五场G-subsequence 1 DP

    G-subsequence 1

    题意

    给你两个字符串(s、t),问(s)中有多少个子序列能大于(t)

    思路

    (len1)(s)的子序列的长度,(lent)(t)的长度

    1. (len1 > lent):枚举每一位,如果当前为不为(0)那么它后面的位置可以随意取,(num = num + inom{k}{len-1}、k)是当前位到(s)的末尾剩下的位数
    2. (len1 = lent):暴力(n^3)肯定超时,所以要用(dp)优化
      (dp[i][j][1])(s[j])作为第(i)个数大于(t[1)~(i])前缀的个数
      (dp[i][j][2])(s[j])作为第(i)个数等于(t[1)~(i])前缀的个数
      • (s[j] > t[i])(dp[i][j][1] = dp[i-1][1) ~ (j-1][1]+dp[i-1][1) ~ (j-1][2])(dp[i][j][2] = 0)

      • (s[j] = t[i])(dp[i][j][1] = dp[i-1][1) ~ (j-1])(dp[i][j][2] = dp[i-1][1) ~ (j-1][2])

      • (s[j] < t[i])(dp[i][j][1] = dp[i-1][1) ~ (j-1])(dp[i][j][2] = 0)

    3. 用一个前缀和维护一下(dp[i-1])的前缀,就可以把(dp)优化到(n^2)

    AC 代码

    #include<bits/stdc++.h>
    #define mes(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    const int maxn = 3e3+10;
    const ll mod = 998244353;
    struct A{
        int num[3][maxn];
        void init(){
            mes(num, 0);
        }
    }a, b;
    char s[maxn], t[maxn];
    ll dp[maxn][maxn][3];
    ll C[maxn][maxn];
    void init(){	//组合数打表
        C[0][0] = C[1][0] = C[1][1] = 1;
        for(int i = 2; i < maxn;i++){
            for(int j = 0; j <= i; j++){
                C[i][j] = j==0?1:C[i-1][j-1]+C[i-1][j];
                C[i][j] %= mod;
            }
        }
    }
     
    int main(){
        int T, n, m;
        scanf("%d", &T);
        init();
        while(T--){
            scanf("%d%d", &n, &m);
            scanf("%s%s", s+1, t+1);
            ll ans = 0;
            a.init();	//表示dp[i-1]的前缀和
            b.init();	//表示dp[i]的前缀和
            for(int i = 1; i <= n-m; i++){
                if(s[i] != '0')
                    for(int j = m; j <= n-i; j++){
                        ans = (ans + C[n-i][j])%mod;
                    }
            }
            for(int i = 0; i <= n; i++){	//初始化
                a.num[2][i] = 1;		
            }
            for(int i = 1; i <= m; i++){
                for(int j = 1; j <= n; j++){
                    if(s[j] > t[i]){
                        dp[i][j][1] = (a.num[1][j-1]+a.num[2][j-1])%mod;
                        dp[i][j][2] = 0;
                    }
                    else if(s[j] == t[i]){
                        dp[i][j][1] = a.num[1][j-1];
                        dp[i][j][2] = a.num[2][j-1];
                    }
                    else{
                        dp[i][j][1] = a.num[1][j-1];
                        dp[i][j][2] = 0;
                    }
                    b.num[1][j] = (b.num[1][j-1] + dp[i][j][1])%mod;
                    b.num[2][j] = (b.num[2][j-1] + dp[i][j][2])%mod;
                }
                swap(a, b);
                b.num[1][0] = b.num[2][0] = 0;
            }
            ans = (ans + a.num[1][n])%mod;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    提高github下载速度
    小程序兼容问题
    求斐波拉契数列第n位算法优化
    并发编程:ThreadLocal
    MySQL:常见面试题
    2.1语法基础_表达式目录树(EF底层原理的实现)
    ajax发送post请求:
    投资是普通人摆脱阶层固化的唯一靠谱方式
    人脸识别之Python基于OpenCV
    搜索算法“一二”基于VSCode平台C#语言
  • 原文地址:https://www.cnblogs.com/zhuyou/p/11286010.html
Copyright © 2011-2022 走看看