• Solution -「Gym 102759G」LCS 8


    (mathcal{Description})

      Link.

      给定 (m),和长度为 (n),字符集为大写字母的字符串 (s),求字符集相同且等长的字符串 (t) 的数量,使得 (s,t) 的 LCS 长度不小于 (n-m)。答案模 ((10^9+7))

      (nle5 imes10^4)(mle3)

    (mathcal{Solution})

      有个傻瓜怕不是忘了 DP of DP 这种东西。

      LCS 的 DP 信息是很方便压缩储存的,在决策 (t_{i+1}) 时,我们希望知道 (g_{i,max{0,i-m}..min{n,i+m}})(g_{i,j})(s[:i])(t[:j]) 的 LCS),记录第一个位置和其对应下标的差值(不超过 (m))以及后面位置的差分((01) 状态),可以得到一个 ((m+1)2^{2m}) 的压缩,转移枚举在这 (mathcal O(m)) 个内的字符,整体转移不在的字符,最劣复杂度为 (mathcal O(nm^22^{2m})),不过明显跑不满。

    (mathcal{Code})

      写得很丑就试了 qwq。

    /*~Rainybunny~*/
    
    #include <cstdio>
    #include <cassert>
    #include <cstring>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    const int MAXN = 5e4, MAXM = 3, MOD = 1e9 + 7;
    int n, m, f[2][MAXM + 1][1 << 2 * MAXM];
    char str[MAXN + 5];
    
    /*
    f(i,i-m), f(i,j-m+1), ..., f(i,i+m)
        x   ,    +[0]   , +[...], +[2m-1]
    */
    
    inline int imin( const int a, const int b ) { return a < b ? a : b; }
    inline int imax( const int a, const int b ) { return a < b ? b : a; }
    inline int mul( const int a, const int b ) { return int( 1ll * a * b % MOD ); }
    inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }
    
    int main() {
        scanf( "%s %d", str + 1, &m ), n = int( strlen( str + 1 ) );
        str[0] = -1; rep ( i, 1, n ) str[i] -= 'A';
    
        f[0][0][0] = 1;
        for ( int i = 0, sta = 0; i < n; ++i, sta ^= 1 ) {
            rep ( j, 0, m ) rep ( S, 0, ( 1 << 2 * m ) - 1 ) {
                int& cur = f[sta][j][S];
                if ( !cur ) continue;
                // printf( "f(%d,%d,%d)=%d
    ", i, j, S, cur );
                static bool vis[26] = {}; int cnt = 0;
                int tp = imax( i - m, 0 ), sp = imax( i - m + 1, 0 ), u, v;
    
                rep ( t, sp, imin( i + m + 1, n ) ) if ( t && !vis[str[t]] ) {
                    int c = str[t]; vis[c] = true, ++cnt;
                    int las[2] = { imax( i - m, 0 ) - j, 0 }, fir = 0, T = 0;
                    // f(i,j)=max{f(i-1,j),f(i,j-1),f(i-1,j-1)+1}.
                    rep ( k, sp, imin( i + m + 1, n ) ) {
                        u = las[0] + ( S >> ( k - tp - 1 ) & 1 );
                        v = imax( imax( las[1], u ), las[0] + ( str[k] == c ) );
                        if ( k == sp ) {
                            fir = k - v;
                            if ( fir > m ) break;
                        } else T |= ( v > las[1] ) << ( k - sp - 1 );
                        las[0] = u, las[1] = v;
                    }
                    if ( fir <= m ) addeq( f[!sta][fir][T], cur );
                }
                {
                    int las[2] = { imax( i - m, 0 ) - j, 0 }, fir = 0, T = 0;
                    rep ( k, sp, imin( i + m + 1, n ) ) {
                        u = las[0] + ( S >> ( k - tp - 1 ) & 1 );
                        v = imax( las[1], u );
                        if ( k == sp ) {
                            fir = k - v;
                            if ( fir > m ) break;
                        } else T |= ( v > las[1] ) << ( k - sp - 1 );
                        las[0] = u, las[1] = v;
                    }
                    if ( fir <= m ) addeq( f[!sta][fir][T], mul( cur, 26 - cnt ) );
                }
    
                rep ( t, sp, imin( i + m + 1, n ) ) if ( t ) vis[str[t]] = false;
                cur = 0;
            }
        }
    
        int ans = 0;
        rep ( i, 0, m ) rep ( S, 0, ( 1 << 2 * m ) - 1 ) {
            // if ( f[n & 1][i][S] )
            //     printf( "f(%d,%d,%d)=%d
    ", n, i, S, f[n & 1][i][S] );
            assert( !f[n & 1][i][S] || !( S >> m ) );
            if ( imax( n - m, 0 ) - i + __builtin_popcount( S ) >= n - m ) {
                addeq( ans, f[n & 1][i][S] );
            }
        }
        printf( "%d
    ", ans );
        return 0;
    }
    
    
  • 相关阅读:
    判别式模型与生成式模型
    C#和Excel进行报表开发
    C# TreeView序列化、串行化、反序列化
    磁盘碎片整理后电脑盘损坏的修复过程
    用C#实现CS模式下软件自动在线升级
    win10家庭版更改为企业版和激活
    [原创]前端页面检查神器google chrome lighthouse
    [原创] PDMReaderSetup下载
    SpringBoot定时任务@EnableScheduling
    【spring bean】@Resource注解的自动注入策略 , 以 项目中注入多个线程池的Bean为例 附加自定义SpringBeanSupport
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15145939.html
Copyright © 2020-2023  润新知