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;
    }
}
原文地址:https://www.cnblogs.com/siuginhung/p/9616106.html