1. 程式人生 > >ACM-ICPC 2018 徐州賽區網絡預賽 A. Hard to prepare

ACM-ICPC 2018 徐州賽區網絡預賽 A. Hard to prepare

傳送門 begin ini main over -- ger == 合數

傳送門: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,其他的滿足上述條件的鏈的狀態數。

於是,有以下轉移方程:

$\begin{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}$

可以寫成矩陣乘法的形式:

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

初始條件:

$\begin{pmatrix}
a_1\\
b_1\\
c_1
\end{pmatrix}
=\begin{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; } }

ACM-ICPC 2018 徐州賽區網絡預賽 A. Hard to prepare