题目链接
题意:
有 一 个 4 ∗ n 的 网 格 有一个4*n的网格 有一个4∗n的网格
有 无 数 个 1 ∗ 2 的 骨 牌 , 可 以 旋 转 有无数个1*2的骨牌,可以旋转 有无数个1∗2的骨牌,可以旋转
问 把 他 铺 满 网 格 有 多 少 方 案 数 问把他铺满网格有多少方案数 问把他铺满网格有多少方案数
题解:
首 先 我 们 假 设 f ( n ) 表 示 4 ∗ n 网 格 的 方 案 数 首先我们假设f(n)表示4*n网格的方案数 首先我们假设f(n)表示4∗n网格的方案数
那 么 可 以 发 现 , 他 是 通 过 前 几 个 补 充 转 移 来 的 那么可以发现,他是通过前几个补充转移来的 那么可以发现,他是通过前几个补充转移来的
那 么 就 有 f n = ∑ i = 1 n − 1 a i ∗ f n − i 那么就有f_n=\sum^{n - 1}_{i=1}a_i*f_{n - i} 那么就有fn=∑i=1n−1ai∗fn−i
但 是 a i 需 要 去 找 一 下 规 律 , 因 为 可 能 a n 和 a n − 1 会 有 重 复 但是a_i需要去找一下规律,因为可能a_n和a_{n-1}会有重复 但是ai需要去找一下规律,因为可能an和an−1会有重复
然 后 手 画 出 来 几 个 可 以 发 现 , 其 实 就 是 对 4 ∗ 1 , 4 ∗ 2 然后手画出来几个可以发现,其实就是对4*1,4*2 然后手画出来几个可以发现,其实就是对4∗1,4∗2
类 似 这 些 进 行 补 充 , 去 除 重 复 的 类似这些进行补充,去除重复的 类似这些进行补充,去除重复的
a 1 = 1 , a 2 = 4 , a 3 = 2 , a 4 = 3 , a 5 = 2 , a 6 = 3 a_1=1,a_2=4,a_3=2,a_4=3,a_5=2,a_6=3 a1=1,a2=4,a3=2,a4=3,a5=2,a6=3
会 发 现 a 1 = 1 , a 2 = 4 , n < = 2 会发现a_1=1,a_2=4, n<=2 会发现a1=1,a2=4,n<=2
a i = 2 , n % 2 = = 1 a_i=2,n \% 2 ==1 ai=2,n%2==1
a i = 3 , n % 2 = = 0 a_i=3,n\%2==0 ai=3,n%2==0
那 么 公 式 就 可 以 改 为 那么公式就可以改为 那么公式就可以改为
f n = f n − 1 + 4 f n − 2 + 2 f n − 3 + 3 f n − 4 + … … f_n=f_{n-1}+4f_{n-2}+2f_{n-3}+3f_{n-4}+…… fn=fn−1+4fn−2+2fn−3+3fn−4+……
然 后 f n − 2 = f n − 3 + 4 f n − 4 + 2 f n − 5 + 3 f n − 6 然后f_{n-2}=f_{n-3}+4f_{n-4}+2f_{n-5}+3f_{n-6} 然后fn−2=fn−3+4fn−4+2fn−5+3fn−6
那 么 式 子 就 成 了 f n = f n − 1 + 5 f n − 2 + f n − 3 − f n − 4 那么式子就成了f_n=f_{n-1}+5f_{n-2}+f_{n-3}-f_{n-4} 那么式子就成了fn=fn−1+5fn−2+fn−3−fn−4
公 式 一 有 , 很 明 显 是 个 线 性 公 式 , 那 么 直 接 用 矩 阵 快 速 幂 列 式 解 决 公式一有,很明显是个线性公式,那么直接用矩阵快速幂列式解决 公式一有,很明显是个线性公式,那么直接用矩阵快速幂列式解决
AC代码
/*
Author : zzugzx
Lang : C++
Blog : blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod = 1e9 + 7;
//const int mod = 998244353;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int maxn = 1e6 + 10;
const int N = 1e2 + 5;
const ll inf = 0x3f3f3f3f;
const int dir[][2]={{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
int mod;
ll Pow(ll a, ll b){
ll ans = 1;
while(b > 0){
if(b & 1){
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll inv(ll b){
return Pow(b,mod-2)%mod;
}
class mat {
public:
int n,m;
ll v[N][N], is[N], js[N];
mat(int n,int m) : n(n), m(m){ memset(v, 0, sizeof(v));}
void init() {
memset(v, 0, sizeof(v));
}
void init1() {
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
v[i][j] = (i == j); //单位矩阵
}
mat operator * (const mat B) const {//矩阵乘法 A(n,k)*B(k,m)=C(n,m);
mat C(n, B.m);
C.init();
for(int i = 0; i < n; i++)
for(int j = 0; j < B.m; j++)
for(int k = 0; k < m; k++)
C.v[i][j] = (C.v[i][j]+v[i][k]*B.v[k][j]) % mod;//Mod
return C;
}
mat operator ^ (int t)//矩阵快速幂 n=m时可用
{
mat ans(n, n), now(n, n);
ans.init1();
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
now.v[i][j] = v[i][j];
while(t > 0) {
if(t & 1) ans = ans * now;
now = now * now;
t >>= 1;
}
return ans;
}
void change() { // 转置
swap(n, m);
for(int i = 0; i < max(n, m); i++) {
for(int j = i + 1; j < max(n, m); j++) {
swap(v[i][j], v[j][i]);
}
}
}
void Minv() { // 逆矩阵
for(int k = 0; k < n; k++) {
for(int i = k; i < n; i++) // 1
for(int j = k; j < n; j++)
if(v[i][j]) {
is[k] = i;
js[k] = j;
break;
}
for(int i = 0; i < n; i++) // 2
swap(v[k][i], v[is[k]][i]);
for(int i = 0; i < n; i++)
swap(v[i][k], v[i][js[k]]);
v[k][k] = inv(v[k][k]); // 3
for(int j = 0; j < n; j++)
if(j != k) // 4
v[k][j] = v[k][j] * v[k][k] % mod;
for(int i = 0; i < n; i++)
if(i != k) // 5
for(int j = 0; j < n; j++)
if(j != k)
v[i][j] = (v[i][j] + mod - v[i][k] * v[k][j] % mod) % mod;
for(int i = 0; i < n; i++)
if(i != k)
v[i][k] = (mod - v[i][k] * v[k][k] % mod) % mod;
}
for(int k = n - 1; k >= 0; k--) { // 6
for(int i = 0; i < n; i++)
swap(v[js[k]][i], v[k][i]);
for(int i = 0; i < n; i++)
swap(v[i][is[k]], v[i][k]);
}
}
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int _;
cin >> _;
while (_--) {
mat A(4, 1), B(4, 4);
B.v[0][0] = B.v[0][2] = 1;
B.v[0][1] = 5, B.v[0][3] = -1;
B.v[1][0] = B.v[2][1] = B.v[3][2] = 1;
A.v[0][0] = 36, A.v[1][0] = 11;
A.v[2][0] = 5, A.v[3][0] = 1;
int n;
cin >> n >> mod;
if (n <= 4) cout << A.v[4 - n][0] << endl;
else {
mat C = (B ^ (n - 4)) * A;
cout << (C.v[0][0] + mod) % mod << endl;
}
}
return 0;
}