P5059 中国象棋

P5059 中国象棋

首先中国象棋是放在格点上的,所以先 \(n \gets n+1\) 转化为放在方格上。样例因为这个看了好久没看懂

又由于每个卒只能攻击与其相邻的两个卒,所以容易发现行与行之间是独立的,所以只考虑一行中的情况。

对于每行至少放两个棋子的限制,可以先抛开不管,最后减去只放一个或不放的 \(n+1\) 种情况。

\(dp_{i,1/0}\) 表示在当前行中考虑到第 \(i\) 位,第 \(i\) 位放或不放的方案数,由于不能有相邻的两个卒,于是可以得到如下转移:

\[\begin{aligned} &dp_{i,1}=dp_{i-1,0}\\ &dp_{i,0}=dp_{i-1,1}+dp_{i-1,0}\\ \end{aligned} \]

因为 \(N \leq 10^{18}\),所以可以用矩阵加速 \(\text{dp}\)

\[\begin{vmatrix}dp_{i-1,0}&dp_{i-1,1}\end{vmatrix}\begin{vmatrix}1&1\\1&0\end{vmatrix}=\begin{vmatrix}dp_{i,0}&dp_{i,1}\end{vmatrix} \]

求出每一行的方案以后,根据乘法原理,总方案数为每行的方案数之积。

计算过程可能爆 \(\text{long long}\),要开 \(\text{int128}\)

时间复杂度 \(O(8 \log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll SIZE = 200005;
ll n, mod;

inline ll rd(){
	ll f = 1, x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return f*x;
}

inline void wt(ll x) {
	if(x<0) {
		putchar('-');
		x=-x;
	}
	if(x>9)
		wt(x/10);
	putchar(x%10+'0');
}

struct node{
	ll o[2][2];
	node(){
		for(ll i = 0; i < 2; i++)
			for(ll j = 0; j < 2; j++)
				o[i][j] = 0;
	}
};

node mul(node A, node B){
	node jl;
	for(ll i = 0; i < 2; i++)
		for(ll j = 0; j < 2; j++)
			for(ll k = 0; k < 2; k++)
				jl.o[i][j] = (jl.o[i][j] + ((__int128)A.o[i][k] * B.o[k][j] % mod)) % mod;	
	return jl;
}

node power(node x, ll y){
	node jl;
	for(ll i = 0; i < 2; i++) jl.o[i][i] = 1;
	while(y){
		if(y&1) jl = mul(jl, x);
		x = mul(x, x);
		y >>= 1;
	}
	return jl;
}

ll power(ll x, ll y){
	ll jl = 1;
	while(y){
		if(y&1) jl = ((__int128)jl *  x) % mod;
		x = ((__int128)x * x) % mod;
		y >>= 1;
	}	
	return jl;
}

int main(){
	n = rd()+1, mod = rd();
	if(n <= 2){
		printf("0");
		return 0;
	}
	node ans;
	ans.o[0][0] = ans.o[0][1] = ans.o[1][0] = 1; ans.o[1][1] = 0;
	ans = power(ans, n-1);
	ll jl = ((ans.o[0][0] + ans.o[0][1])%mod + (ans.o[1][0] + ans.o[1][1])%mod)%mod;
	jl = ((jl - n - 1) % mod + mod) % mod;
	wt(power(jl, n));
	return 0;
}

posted @ 2023-07-09 08:47  Semorius  阅读(39)  评论(0)    收藏  举报