Live2D

Solution -「Gym 102759G」LCS 8

Description

  Link.

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

  n5×104m3

Solution

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

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

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\n", 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", 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\n", ans );
    return 0;
}

posted @   Rainybunny  阅读(150)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示