• ACM-ICPC 2018 徐州赛区网络预赛 A. Hard to prepare


    传送门:https://nanti.jisuanke.com/t/31453

    本题是一个组合数学(DP,滑稽)题。

    一个环上有N个位置,标号为1~N。设第i(1≤i≤N)个位置上的数为x[i],限制条件为:0≤x[i]<2k。另有限制条件:当位置i和位置j相邻时,x[i]x[j]≠2k-1。求满足限制条件的环的状态数。

    可以考虑将环切割成链,以分析问题。设:

    a[n]:长度为n,且首尾相同的满足上述条件的链的状态数;

    b[n]:长度为n,且首尾相反的满足上述条件的链的状态数;

    c[n]:长度为n,其他的满足上述条件的链的状态数。

    于是,有以下转移方程:

    $egin{cases}
    a_n=a_{n-1}+c_{n-1} \
    b_n=b_{n-1}+c_{n-1} \
    c_n=(2^k-3)c_{n-1}
    end{cases}$

    可以写成矩阵乘法的形式:

    $egin{pmatrix}
    a_i\
    b_i\
    c_i
    end{pmatrix}
    =egin{pmatrix}
    1 & 0 & 1\
    0 & 1 & 1\
    2^k-2 & 2^k-2 & 2^k-3
    end{pmatrix}
    egin{pmatrix}
    a_{i-1}\
    b_{i-1}\
    c_{i-1}
    end{pmatrix}$

    初始条件:

    $egin{pmatrix}
    a_1\
    b_1\
    c_1
    end{pmatrix}
    =egin{pmatrix}
    2^k\
    0\
    0
    end{pmatrix}$

    可以通过矩阵快速幂在O(logN)时间内求解。

    答案为$ans(N,k)=(2^k-1)a_{N-1}+(2^k-2)(b_{N-1}+c_{N-1})$。

    参考程序如下(实现上引用了本人编写的矩阵类的部分代码):

    #include <bits/stdc++.h>
    using namespace std;
    
    const int64_t mod = 1e9 + 7;
    
    int64_t pwr(int64_t x, int p)
    {
        if (p == 0) return 1;
        if (p & 1) return x * pwr(x, p ^ 1) % mod;
        return pwr(x * x % mod, p >> 1);
    }
    
    int64_t a[3][3];
    
    #define MAX_N 3
    
    /***
     * Matrix is a type of 2D-array.
     * Here implements Basic Operators of Matrix.
     */
    struct Matrix_t {
        int row, col;
        int64_t elem[MAX_N][MAX_N];
        Matrix_t() {}
        Matrix_t(int row, int col) : row(row), col(col) {}
        Matrix_t(int row, int col, int64_t elem[][MAX_N]) {
            this->row = row;
            this->col = col;
            if (elem != nullptr) {
                for (int i = 0; i < row; i++) {
                    for (int j = 0; j < col; j++) {
                        this->elem[i][j] = elem[i][j];
                    }
                }
            }
        }
        Matrix_t(const Matrix_t& obj) {
            this->row = obj.row;
            this->col = obj.col;
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    this->elem[i][j] = obj.elem[i][j];
                }
            }
        }
        virtual ~Matrix_t() {
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    elem[i][j] = 0;
                }
            }
            row = 0;
            col = 0;
        }
        Matrix_t& operator =(const Matrix_t& rhs) {
            row = rhs.row;
            col = rhs.col;
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    elem[i][j] = rhs.elem[i][j];
                }
            }
            return *this;
        }
        //Override: Matrix Multiplication.
        Matrix_t operator *(const Matrix_t& rhs) {
            int64_t res[MAX_N][MAX_N];
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < rhs.col; j++) {
                    res[i][j] = 0;
                    for (int k = 0; k < col; k++) {
                        res[i][j] += elem[i][k] * rhs.elem[k][j] % mod;
                        res[i][j] %= mod;
                    }
                }
            }
            return Matrix_t(row, rhs.col, res);
        }
    };
    
    /***
     * Square Mairtx is a type of Matrix.
     * Here implements Integer Power of Square Matrix.
     */
    struct SquareMatrix_t : Matrix_t {
        int sz;
        SquareMatrix_t() {}
        SquareMatrix_t(int sz) : Matrix_t(sz, sz), sz(sz) {}
        SquareMatrix_t(int sz, int64_t elem[][MAX_N]) : Matrix_t(sz, sz, elem), sz(sz) {}
        virtual ~SquareMatrix_t() {
            for (int i = 0; i < sz; i++) {
                for (int j = 0; j < sz; j++) {
                    elem[i][j] = 0;
                }
            }
            sz = 0;
        }
        void init() {
            for (int i = 0; i < sz; i++) {
                elem[i][i] = 1;
            }
        }
        SquareMatrix_t& operator =(const Matrix_t& rhs) {
            sz = rhs.row;
            for (int i = 0; i < sz; i++) {
                for (int j = 0; j < sz; j++) {
                    elem[i][j] = rhs.elem[i][j];
                }
            }
            return *this;
        }
        SquareMatrix_t operator ^(int p) {
            SquareMatrix_t res(sz);
            SquareMatrix_t tmp(*this);
            res.init();
            while (p) {
                if (p & 1) res = res * tmp;
                tmp = tmp * tmp;
                p >>= 1;
            }
            return res;
        }
    };
    
    int main(void)
    {
        ios::sync_with_stdio(false);
        int t;
        cin >> t;
        while (t--) {
            memset(a, 0, sizeof(a));
            int n, k;
            cin >> n >> k;
            int64_t p = pwr(2, k);
            if (n == 1) {
                cout << p << endl;
                continue;
            }
            a[0][0] = 1;
            a[0][2] = 1;
            a[1][1] = 1;
            a[1][2] = 1;
            a[2][0] = (p - 2 + mod) % mod;
            a[2][1] = (p - 2 + mod) % mod;
            a[2][2] = (p - 3 + mod) % mod;
            SquareMatrix_t mat(3, a);
            SquareMatrix_t res = mat ^ (n - 2);
            int64_t a = res.elem[0][0] * p % mod;
            int64_t b = res.elem[1][0] * p % mod;
            int64_t c = res.elem[2][0] * p % mod;
            int64_t ans = (a * ((p - 1 + mod) % mod) % mod + (b + c) % mod * ((p - 2 + mod) % mod) % mod) % mod;
            cout << ans << endl;
        }
    }
  • 相关阅读:
    第6周编程题:零基础学Java
    帆软报表软件学习计划
    北大软件工程——第八周:面向对象设计2
    hdu1264 Counting Squares
    hdu1264 Counting Squares
    poj1151 Atlantis(线段树+扫描线)
    poj1151 Atlantis(线段树+扫描线)
    bzoj4653 [Noi2016]区间
    bzoj4653 [Noi2016]区间
    Tyvj1043
  • 原文地址:https://www.cnblogs.com/siuginhung/p/9616106.html
Copyright © 2020-2023  润新知