• 牛客-拆分(矩阵乘法)


    题目大意

    (n)个数,现在把它们划分成若干段,使存在一段的数的个数不为给出的(k)个数中的任意一个。问有多少种划分方式

    (nle10^{18})

    给出的(k)个数任意一个保证不超过(100)

    分析

    一个很明显的做法:先求出没有限制条件的总方案数

    (C^1_{n-1}+C^2_{n-1}+C^3_{n-1}+dots+C^{n-1}_{n-1}+1)

    这个值就是(2^{n-1})

    接下来考虑减去特殊的情况

    特殊情况即为:对于每个划分出来的段,个数都是给出的(k)个数之中的其中一个

    考虑(DP)

    (f_i)表示划分到第(i)个数,共有几种情况

    转移方程即为:

    [f_i=sumlimits_{j=1}^{k}{f_{i-t_j}} ]

    看到(n)特别大,想到矩乘。

    构建状态矩阵

    (egin{bmatrix}f_i&f_{i-1}&f_{i-2}&dots&f_{i-100}end{bmatrix})

    转移矩阵

    第一列(t_i)位为(1),其余为(0)

    其他列只有(i-1)位为(1),其余为(0)

    #include <bits/stdc++.h>
    #define int long long
    using namespace std ;
    int n , p , k ;
    int a[ 110 ] ;
    struct Matrix {
        int a[ 110 ][ 110 ] ;
        void clear () { memset ( a , 0 , sizeof ( a ) ) ; }
    } ans , b ;
    Matrix operator * ( Matrix A , Matrix B ) {
        Matrix C ;
        C.clear () ;
        for ( int i = 1 ; i <= 100 ; i ++ )
            for ( int j = 1 ; j <= 100 ; j ++ )
                for ( int k = 1 ; k <= 100 ; k ++ )
                    C.a[ i ][ j ] = ( C.a[ i ][ j ] + A.a[ i ][ k ] * B.a[ k ][ j ] ) % p ;
        return C ;
    }
    inline int qpow ( int a , int b ) {
        int res = 1 ;
        while ( b ) {
            if ( b & 1 ) res = res * a % p ;
            a = a * a % p ;
            b >>= 1 ;
        }
        return res ;
    }
    inline void Matrix_pow ( int bs ) {
        while ( bs ) {
            if ( bs & 1 ) ans = ans * b ;
            b = b * b ;
            bs >>= 1 ;
        }
    }
    signed main () {
        ios :: sync_with_stdio ( false ) ;
        cin >> n >> p >> k ;
        b.clear () ;
        for ( int i = 1 ; i <= k ; i ++ ) {
            int t ; cin >> t ;
            b.a[ t ][ 1 ] = 1 ;
        }
        for ( int i = 2 ; i <= 100 ; i ++ ) b.a[ i - 1 ][ i ] = 1 ;
        ans.a[ 1 ][ 1 ] = 1 ;
        Matrix_pow ( n ) ;
        printf ( "%lld
    " , ( qpow ( 2 , n - 1 ) - ans.a[ 1 ][ 1 ] + p ) % p ) ;
        return 0 ;
    }
    
  • 相关阅读:
    [转] 接触C# 反射 2
    [转] C#操作Excel文件
    【Leetcode】Path Sum II
    java通用抹去魔,在边界行动,擦除补偿
    python抓取网络内容
    一个合格的程序猿编程
    Android的相关的源代码的方法
    随笔
    使用方便git命令检查记录的版本号
    opengl 扳回一球
  • 原文地址:https://www.cnblogs.com/hulean/p/13647622.html
Copyright © 2020-2023  润新知