zoukankan      html  css  js  c++  java
  • [XR-1]分块

    [XR-1]分块

    [XR-1]分块

    这题其实就是问把一段序列划分成若干个子段并限制子段大小的方案数.

    首先,要把子段的大小集合搞出来.这其实就是求两个不可重集合的交.

    可以直接用桶,我用了 (set) , 要稍微麻烦一些.

    去重之后,就可以直接 (Dp) 了,令 (f_n) 表示长度为 (n) 的序列的方案数.

    那么转移显然有:

    [f_n=sum_{i=1}^m{[nge v_i] imes f_{n-v_i}} ]

    其中 , (v_i) 是子段大小集合, (m) 是子段大小的个数 , ([x]) 当且仅当 (x) 表达式为真时为 (1) , 否则为 (0) .

    这样的复杂度是 (Theta(n imes max{v_i})) 的,足以通过 (60\%) 的数据.

    那么对于 (100\%) 的数据该怎么去做呢?

    我们发现 (n) 的范围高达 (10^{18}) , 能做到这样复杂度且被我们熟知的算法只有 (Theta(size^3 imes log_2{n})) 的矩乘.

    并且我们发现,这个 (DP) 实际上就是至多有 (100) 个相关状态的递推.

    所以完全可以尝试构造转移矩阵.

    显然,这个转移矩阵应该是 (100 imes 100) 的.

    那么我们先确定初始矩阵是什么样子 (:)

    [left[egin{array}{llll} f_{size-1} & f_{size-2} & ... & f_{0}end{array} ight] ]

    它非常的正常,除了有点长.

    目标矩阵呢?

    [left[egin{array}{llll} f_{size} & f_{size} & ... & f_{1}end{array} ight] ]

    转移矩阵呢?

    [left[egin{array}{llll} ? & ? & ... & ? & ? \ ? & ? & ... & ? & ? \ ? & ? & ... & ? & ? \ &&...&& \ ? & ? & ... & ? & ? \ ? & ? & ... & ? & ? \ ? & ? & ... & ? & ? end{array} ight] ]

    (100 imes 100) 的,因为你要保留所有状态,他们都可能是有用的.

    他长什么样呢?

    第一列中显然所有的 (v_i) 对应的位置都是 (1) , 其他列呢?

    显然都可以从上一个矩阵直接抠下来,所以只有 ((i,i+1))(1) .

    然后转移就完了.

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <ctime>
    #include <map>
    #include <set>
    #define MEM(x,y) memset ( x , y , sizeof ( x ) )
    #define rep(i,a,b) for (int i = (a) ; i <= (b) ; ++ i)
    #define per(i,a,b) for (int i = (a) ; i >= (b) ; -- i)
    #define pii pair < int , int >
    #define one first
    #define two second
    #define rint read<int>
    #define int long long
    #define pb push_back
    #define db double
    #define ull unsigned long long
    #define lowbit(x) ( x & ( - x ) )
    
    using std::queue ;
    using std::set ;
    using std::pair ;
    using std::max ;
    using std::min ;
    using std::priority_queue ;
    using std::vector ;
    using std::swap ;
    using std::sort ;
    using std::unique ;
    using std::greater ;
    
    template < class T >
        inline T read () {
            T x = 0 , f = 1 ; char ch = getchar () ;
            while ( ch < '0' || ch > '9' ) {
                if ( ch == '-' ) f = - 1 ;
                ch = getchar () ;
            }
           while ( ch >= '0' && ch <= '9' ) {
                x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
                ch = getchar () ;
           }
           return f * x ;
        }
    
    const int N = 1e6 + 100 ;
    const int mod = 1e9 + 7 ;
    set < int > rab , fis , tmp ; int maxv = - 1 ;
    int f[N] , n , pr , nf , v[N] , cnt ;
    
    struct Matrix {
        int e[105][105] , line , row ;
    
        inline void clear () { MEM ( e , 0 ) ; line = row = 0 ; return ; }
    
        inline void init () { rep ( i , 1 , line ) e[i][i] = 1 ; }
    
        friend Matrix operator * (Matrix a , Matrix b) {
            Matrix res ; res.clear () ; res.line = a.line ; res.row = b.row ;
            rep ( k , 1 , a.row ) rep ( i , 1 , a.line ) rep ( j , 1 , b.row )
                res.e[i][j] = ( res.e[i][j] + a.e[i][k] * b.e[k][j] % mod ) % mod ;
            return res ;
        }
    
        friend Matrix operator ^ (Matrix a , int p) {
            Matrix res ; res.clear () ; res.line = res.row = a.line ; res.init () ;
            while ( p ) {
                if ( p & 1 ) res = res * a ;
                a = a * a ; p >>= 1 ;
            }
            return res ;
        }
    } mat , ans ;
    
    signed main (int argc , char * argv[]) {
        n = rint () ;
        pr = rint () ; rep ( i , 1 , pr ) rab.insert ( rint () ) ;
        nf = rint () ; rep ( i , 1 , nf ) fis.insert ( rint () ) ;
        for (auto it = rab.begin () ; it != rab.end () ; ++ it) {
            int reg = *it ;
            if ( fis.find ( reg ) == fis.end () ) continue ;
            tmp.insert ( reg ) ;
        }
        for (auto it = tmp.begin () ; it != tmp.end () ; ++ it) v[++cnt] = *it ;
        rep ( i , 1 , cnt ) f[v[i]] = 1 ;
        rep ( i , 1 , 100 ) rep ( j , 1 , cnt ) {
            if ( i - v[j] < 0 ) continue ;
            f[i] = ( f[i] + f[i-v[j]] ) % mod ;
        }
        if ( n <= 100 ) return printf ("%lld
    " , f[n] ) , 0 ;
        mat.clear () ; ans.clear () ;
        rep ( i , 1 , cnt ) mat.e[v[i]][1] = 1 ;
        rep ( i , 1 , 100 ) mat.e[i][i+1] = 1 ;
        mat.line = mat.row = 100 ; ans.line = 1 ; ans.row = 100 ;
        rep ( i , 1 , 100 ) ans.e[1][i] = f[100-i] ;
        mat = mat ^ n ; ans = ans * mat ;
        printf ("%lld
    " , ans.e[1][100] % mod ) ;
        return 0 ;
    }
    
  • 相关阅读:
    MATLAB新手教程
    关于Core Location-ios定位
    《TCP/IP具体解释卷2:实现》笔记--IP的分片和重装
    利用JasperReport+iReport进行Web报表开发
    Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
    Openfire开发配置,Openfire源码配置,OpenFire二次开发配置
    在Activity中为什么要用managedQuery()
    24点经典算法
    linux概念之时间与时区
    java实现第五届蓝桥杯大衍数列
  • 原文地址:https://www.cnblogs.com/Equinox-Flower/p/11724301.html
Copyright © 2011-2022 走看看