zoukankan      html  css  js  c++  java
  • Solution -「Gym 102956B」Beautiful Sequence Unraveling

    (mathcal{Description})

      Link.

      求长度为 (n),值域为 ([1,m]) 的整数序列 (lang a_n ang) 的个数,满足 ( otexist iin[1,n),~max_{j=1}^i{a_j}=min_{j=i+1}^n{a_j}),答案对大素数 (p) 取模。

      (nle400)(mle10^8)

    (mathcal{Solution})

      前几天刚胡了一个 "DP and DP" 的 trick,这不又遇见一道。(

      注意到 (m) 很大,一副拒 DP 状态于千里之外的样子,尝试先回避它——将某个合法 (lang a_n ang) 离散化,此时值域不超过 ([1,n])。但“离散化”又要求值域中每个位置出现,那我们折中:只要求值域为 ([1,n]),而不限制每个位置出现。可是为了将值域还原为 ([1,m]),我们又势必得知“有多少个合法 (lang a_n ang),其中 (a)(x) 种不同取值”。

      一步步来,先考虑求出 (f(i,j)),表示长度为 (i) 的序列,值域在 ([1,j]) 时的合法数量。总数减去不合法数,枚举最后一个不合法位置 (k-1),以及此时前缀 (max) 和后缀 (min) 的值 (t),可以发现 (a_{k..n}) 构成子问题,得到转移

    [f(i,j)=j^i-sum_{k=2}^isum_{t=1}^j(t^{k-1}-(t-1)^{k-1})(f(i-k+1,j-t+1)-f(i-k+1,j-t)). ]

    合理处理系数的指标和转移状态的下标,可以利用前缀和将求 (f) 的过程优化至 (mathcal O(n^3))

      如刚才透露的一般,我们在目标状态 (f(n,1..n)) 的基础下求“有 (x) 个不同取值”。令 (g(i)) 表示长度为 (n) 的序列中,离散化后满足值域恰为 ([1,i]) 的合法数量,简单地

    [g(i)=f(n,i)-sum_{j=1}^{i-1}inom{i}{j}g(j). ]

      答案变得显而易见

    [ extit{answer}=sum_{i=1}^ninom{m}{i}g_i. ]

    其中组合数展开成下降幂暴力算即可。总复杂度 (mathcal O(n^3))

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <cstdio>
    
    #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 = 400;
    int n, m, P, fac[MAXN + 5], ifac[MAXN + 5];
    int pwr[MAXN + 5][MAXN + 5], ipwr[MAXN + 5][MAXN + 5];
    int f[MAXN + 5][MAXN + 5], g[MAXN + 5];
    
    inline int mul( const int a, const int b ) { return 1ll * a * b % P; }
    inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += P ); }
    inline int add( int a, const int b ) { return ( a += b ) < P ? a : a - P; }
    inline void addeq( int& a, const int b ) { ( a += b ) >= P && ( a -= P ); }
    inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + P : a; }
    inline int mpow( int a, int b ) {
        int ret = 1;
        for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
        return ret;
    }
    
    inline void init() {
        fac[0] = 1;
        rep ( i, 1, n ) fac[i] = mul( i, fac[i - 1] );
        ifac[n] = mpow( fac[n], P - 2 );
        per ( i, n - 1, 0 ) ifac[i] = mul( i + 1, ifac[i + 1] );
    
        rep ( i, 0, n ) {
            pwr[i][0] = ipwr[i][0] = 1;
            ipwr[i][1] = mpow( pwr[i][1] = i, P - 2 );
            rep ( j, 2, n ) {
                pwr[i][j] = mul( i, pwr[i][j - 1] );
                ipwr[i][j] = mul( ipwr[i][j - 1], ipwr[i][1] );
            }
        }
    }
    
    inline int comb( const int a, const int b ) {
        return a < b ? 0 : mul( fac[a], mul( ifac[b], ifac[a - b] ) );
    }
    
    int main() {
        scanf( "%d %d %d", &n, &m, &P ), init();
    
        rep ( j, 1, n ) {
            static int sum[MAXN + 5][2];
            rep ( i, 1, n ) sum[i][0] = sum[i][1] = 0;
            rep ( i, 1, n ) {
                int& cur = f[i][j] = pwr[j][i];
                rep ( t, 1, j ) {
                    subeq( cur, mul( pwr[t][i], sum[t][0] ) );
                    addeq( cur, mul( pwr[t - 1][i], sum[t][1] ) );
                }
                rep ( t, 1, j ) {
                    addeq( sum[t][0], mul( ipwr[t][i],
                      sub( f[i][j - t + 1], f[i][j - t] ) ) );
                    addeq( sum[t][1], mul( ipwr[t - 1][i],
                      sub( f[i][j - t + 1], f[i][j - t] ) ) );
                }
            }
        }
    
        int ans = 0, c = 1;
        rep ( i, 1, n ) {
            int& cur = g[i] = f[n][i];
            rep ( j, 1, i - 1 ) subeq( cur, mul( comb( i, j ), g[j] ) );
            c = mul( c, mul( m - i + 1, ipwr[i][1] ) );
            addeq( ans, mul( c, g[i] ) );
        }
        printf( "%d
    ", ans );
        return 0;
    }
    
    
  • 相关阅读:
    Gradle中使用SpringBoot插件构建多模块遇到的问题
    使用docker-compose快速构建集群示例(一)
    tensorflow对多维tensor按照指定索引重排序
    tensorflow Dataset及TFRecord一些要点【持续更新】
    RNN、LSTM介绍以及梯度消失问题讲解
    使用BERT模型生成句子序列向量
    给定数字N,输出小于10^N的所有整数
    使用BERT模型生成token级向量
    使用BERT预训练模型+微调进行文本分类
    tensorflow与神经网络中遇到的问题与解决方法【持续更新】
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15182863.html
Copyright © 2011-2022 走看看