1. 程式人生 > 其它 >Solution -「Gym 102956B」Beautiful Sequence Unraveling

Solution -「Gym 102956B」Beautiful Sequence Unraveling

\(\mathcal{Description}\)

  Link.

  求長度為 \(n\),值域為 \([1,m]\) 的整數序列 \(\lang a_n\rang\) 的個數,滿足 \(\not\exist i\in[1,n),~\max_{j=1}^i\{a_j\}=\min_{j=i+1}^n\{a_j\}\),答案對大素數 \(p\) 取模。

  \(n\le400\)\(m\le10^8\)

\(\mathcal{Solution}\)

  前幾天剛胡了一個 "DP and DP" 的 trick,這不又遇見一道。(

  注意到 \(m\) 很大,一副拒 DP 狀態於千里之外的樣子,

嘗試先回避它——將某個合法 \(\lang a_n\rang\) 離散化,此時值域不超過 \([1,n]\)。但“離散化”又要求值域中每個位置出現,那我們折中:只要求值域為 \([1,n]\),而不限制每個位置出現。可是為了將值域還原為 \([1,m]\),我們又勢必得知“有多少個合法 \(\lang a_n\rang\),其中 \(a\)\(x\) 種不同取值”。

  一步步來,先考慮求出 \(f(i,j)\),表示長度為 \(i\) 的序列,值域在 \([1,j]\) 時的合法數量。總數減去不合法數,列舉最後一個不合法位置 \(k-1\),以及此時字首 \(\max\) 和字尾 \(\min\)

的值 \(t\),可以發現 \(a_{k..n}\) 構成子問題,得到轉移

\[f(i,j)=j^i-\sum_{k=2}^i\sum_{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}\binom{i}{j}g(j). \]

  答案變得顯而易見

\[\textit{answer}=\sum_{i=1}^n\binom{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\n", ans );
    return 0;
}