Maybe something will ch|

Semorius

园龄:1年9个月粉丝:4关注:10

2023-07-09 08:47阅读: 20评论: 0推荐: 0

P5059 中国象棋

P5059 中国象棋

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

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

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

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

dpi,1=dpi1,0dpi,0=dpi1,1+dpi1,0

因为 N1018,所以可以用矩阵加速 dp

|dpi1,0dpi1,1||1110|=|dpi,0dpi,1|

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

计算过程可能爆 long long,要开 int128

时间复杂度 O(8logn)

点击查看代码
#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;
}

本文作者:Semorius

本文链接:https://www.cnblogs.com/Semorius/p/17538287.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Semorius  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起