zoukankan      html  css  js  c++  java
  • 限制公共子序列计数 [动态规划]

    限制公共子序列计数


    color{red}{正解部分}

    F[i,j]F[i, j] 表示 SS 序列前 ii 项, TT 序列前 jj 项, iijj 共同作为 公共子序列 末尾的方案数,
    首先有一个很显然的状态转移方程,

    F[i,j]=[Si==Tj]×(k=0i1p=0j1F[k,p])F[i, j] = [S_i==T_j] imes left(sumlimits_{k=0}^{i-1}sumlimits_{p=0}^{j-1} F[k, p] ight) ,时间复杂度 O(N4)O(N^4),

    对于这种 Si=TjS_i = T_j 时才生效的状态, 可以在 SiTjS_i ot = T_j 时, 直接继承, 所以不妨直接省掉一维,

    从小到大 枚举 ii, 设 F[j]F[j] 表示以 Tj,SiT_j, S_i 这个 结尾, 与 SSii 项构成 公共子序列 的方案数量,

    F[j]=k=0j1F[k]F[j] = sum_{k=0}^{j-1} F[k], 意为 以 TkT_k 这个 为末尾 转移到 以 (Tj=Si)(T_j=S_i) 这个 为末尾,

    • 可以发现 SiS_i 在枚举 jj 时是不变的, 因此可以方便的维护限制条件,
    • 随着 jj 从小到大 枚举, 在枚举时不断使用当前 F[j]F[j] 完善决策集合即可实现后面 O(1)O(1) 转移 .

    时间复杂度 O(N2)O(N^2) .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 3005;
    const int mod = 1e9 + 7;
    
    int N;
    int M;
    int K;
    int Len;
    int Ans;
    int num0;
    int S[maxn];
    int T[maxn];
    int B[maxn<<1];
    int F[maxn<<1];
    
    bool is[maxn<<1][maxn<<1];
    
    int main(){
            N = read(), M = read(), K = read();
            for(reg int i = 1; i <= N; i ++) B[++ Len] = S[i] = read();
            for(reg int i = 1; i <= M; i ++) B[++ Len] = T[i] = read();
            std::sort(B+1, B+Len+1);
            Len = std::unique(B+1, B+Len+1) - B-1;
            for(reg int i = 1; i <= N; i ++) S[i] = std::lower_bound(B+1, B+Len+1, S[i])-B;
            for(reg int i = 1; i <= M; i ++) T[i] = std::lower_bound(B+1, B+Len+1, T[i])-B;
            for(reg int i = 1; i <= K; i ++){
                    int s = read(), t = read();
                    int p = std::lower_bound(B+1, B+Len+1, s)-B;
                    if(p == Len+1 || B[p] != s) continue ; s = p;
                    p = std::lower_bound(B+1, B+Len+1, t)-B;
                    if(p == Len+1 || B[p] != t) continue ; t = p;
                    if(is[s][t]) continue ; is[s][t] = 1;
            }
            for(reg int i = 1; i <= N; i ++)
                    for(reg int j = 1, s = 1; j <= M; j ++){
                            int ts = s;
                            if(is[T[j]][S[i]]) s = (s + F[j]) % mod; // 可以转移到后面.
                            if(S[i] != T[j]) continue ;
                            Ans = (Ans + ts) % mod; F[j] = (F[j] + ts) % mod;
                    }
            printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    Android 开发工具类 19_NetworkStateReceiver
    Android 开发工具类 18_NetWorkUtil
    Sticky Footer (让页脚永远停靠在页面底部,而不是根据绝对位置)
    min-height最小高度的实现(兼容IE6、IE7、FF)(解决IE6不兼容min-height)
    不同浏览器设置背景透明度
    讨论内外边距对行内元素是否起作用,则要对行内替换元素和行内非替换元素分别讨论:
    超链接访问过后hover样式就不出现的问题
    解决:子元素设置margin-top,父元素也受影响的问题
    制作0.5px像素的细条
    去掉inline-block元素间隙的几种方法
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822439.html
Copyright © 2011-2022 走看看