【题目大意】

在\(2\times N\)的方格中用\(N-1\)块\(2\times 1\)的方砖和\(2\)块\(1\times 1\)的方砖填充,且两块\(1\times 1\)的方块不能有相邻的边,求合法方案数。

【分析】

啊,一道计数问题。反正我开始是这样想的。

如果没有那两块很碍事的砖,这不就是斐波拉契递推吗?,,,\(f[i]=f[i-1]+f[i-2]\),递推走起。

好,现在来看那两块碍事的砖。

首先,我们会发现,这两块特别的砖会把整个方格分成三个部分,我们假设左右两部分刚好是完整的(即是个矩形),那么中间的块就有性质了。

仔细推一推就会发现,当这两个特殊的块间隔奇数个块时,这两个块必定在相异的两行,并且中间只有一种方案构成。

同样的,当这两个特殊的块间隔偶数个块时,这两个块必定在相同的一行,并且中间也只有一种方案构成。

又因为不能有相邻的边,于是计算公式就出来了。

\[ans = 2 * \sum_{i=0}^{n-3}\sum_{j=0}^{i}f[j]*f[i-j]
\]

细细理解下。

用这个大概只能得\(20pt\),我们想想怎么优化?看到\(N<=2e+9\)的数据范围,当然要往矩阵快速幂上面想咯。

矩阵的推法各有不同吧,我们来一步一步来拆这个式子。

设\(g(i)=\sum_{j=0}^{i}f(j)*f(i-j)\)。

所以

\(\begin{equation}
\begin{aligned}
g(i)&=\sum_{j=0}^{i}f(j)*f(i-j) \\
&=\sum_{j=0}^{i-2}f(j)*f(i-j)+f(i-1)*f(1)+f(i)*f(0)\\
&=\sum_{j=0}^{i-2}f(j)*[f(i-1-j)+f(i-2-j)]+f(i-1)+f(i)\\
&=g(i-2)+g(i-1)+f(i)
\end{aligned}
\end{equation}\)

又设\(sum(i)=\sum_{j=0}^{i}g(j)\)

所以

\(\begin{equation}
\begin{aligned}
sum(i)&=\sum_{j=0}^{i}g(j) \\
&=\sum_{j=0}^{i-1}g(j)+g(i) \\
&=sum(i-1)+g(i-2)+g(i-1)+f(i)
\end{aligned}
\end{equation}\)

所以易推得矩阵转移方程:

\(\begin{equation}{
\left[ \begin{array}{ccc}
f(i) \\
f(i-1) \\
g(i) \\
g(i-1) \\
sum(i) \\
\end{array}
\right ]}\times {
\left[ \begin{array}{ccc}
1 & 1 & 0 & 0 & 0\\
1 & 0 & 0 & 0 & 0 \\
1 & 1 & 1 & 1 & 0 \\
0 & 0 & 1 & 0 & 0 \\
1 & 1 & 1 & 1 & 1 \\
\end{array}
\right ]}={
\left[ \begin{array}{ccc}
f(i+1)\\
f(i)\\
g(i+1)\\
g(i)\\
sum(i+1)
\end{array}
\right ]}
\end{equation}\)

敲公式比敲字累多了。。。

于是\(O(125logn)\)可过。

哦,这个推法有点玄学,需要处理下边界情况,具体情况见代码。

【Code】

#include<ctime>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int MAX = 100000 + 5;
const int mod = 1e9 + 7;
inline int read(){
int f = 1, x = 0;char ch;
do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0'||ch>'9');
do {x = x*10+ch-'0'; ch = getchar(); } while (ch >= '0' && ch <= '9');
return f*x;
} struct sakura {
ll mar[5][5];
}A; int t, n; inline sakura mul(sakura A, sakura B) {
sakura C;
memset(C.mar, 0, sizeof (C.mar));
for (int i = 0;i <= 4; ++i) {
for (int k = 0;k <= 4; ++k) {
for (int j = 0;j <= 4; ++j) {
C.mar[i][j] = (C.mar[i][j] + (A.mar[i][k] * B.mar[k][j]) % mod ) % mod;
}
}
}
return C;
} inline sakura mi(sakura A, int c) {
sakura B;
B.mar[0][0] = 1, B.mar[1][0] = 1, B.mar[2][0] = 2, B.mar[3][0] = 1, B.mar[4][0] = 3;
for (;c;c >>= 1) {
if (c & 1) B = mul(A, B);
A = mul(A, A);
}
return B;
}
int main(){
t = read();
while (t--) {
n = read();
if (n < 3) {
printf("0\n");
continue;
}
if (n == 3) {
printf("2\n");
continue;
}
A.mar[0][0] = 1, A.mar[0][1] = 1, A.mar[0][2] = 0, A.mar[0][3] = 0, A.mar[0][4] = 0;
A.mar[1][0] = 1, A.mar[1][1] = 0, A.mar[1][2] = 0, A.mar[1][3] = 0, A.mar[1][4] = 0;
A.mar[2][0] = 1, A.mar[2][1] = 1, A.mar[2][2] = 1, A.mar[2][3] = 1, A.mar[2][4] = 0;
A.mar[3][0] = 0, A.mar[3][1] = 0, A.mar[3][2] = 1, A.mar[3][3] = 0, A.mar[3][4] = 0;
A.mar[4][0] = 1, A.mar[4][1] = 1, A.mar[4][2] = 1, A.mar[4][3] = 1, A.mar[4][4] = 1;
sakura ans = mi(A, n - 4);
ans.mar[4][0] <<= 1;
ans.mar[4][0] %= mod;
printf("%d\n", ans.mar[4][0]);
}
return 0;
}

【详●析】[GXOI/GZOI2019]逼死强迫症的更多相关文章

  1. 【BZOJ5505】[GXOI/GZOI2019]逼死强迫症(矩阵快速幂)

    [BZOJ5505][GXOI/GZOI2019]逼死强迫症(矩阵快速幂) 题面 BZOJ 洛谷 题解 如果没有那两个\(1*1\)的东西,答案就是斐波那契数,可以简单的用\(dp\)得到. 大概是设 ...

  2. [LOJ3086][GXOI/GZOI2019]逼死强迫症——递推+矩阵乘法

    题目链接: [GXOI/GZOI2019]逼死强迫症 设$f[i][j]$表示前$i$列有$j$个$1*1$的格子的方案数,那么可以列出递推式子: $f[i][0]=f[i-1][0]+f[i-2][ ...

  3. P5303 [GXOI/GZOI2019]逼死强迫症

    题目地址:P5303 [GXOI/GZOI2019]逼死强迫症 这里是官方题解 初步分析 从题目和数据范围很容易看出来这是一个递推 + 矩阵快速幂,那么主要问题在于递推的过程. 满足条件的答案一定是以 ...

  4. luogu P5303 [GXOI/GZOI2019]逼死强迫症

    传送门 只有两行,考虑递推,设\(f_i\)为没有那两个\(1*1\)的,前\(i\)列的方案,可以发现一次可以放一个竖的或两个横的,也就是\(f_i=f_{i-1}+f_{i-2}\) 再设\(g_ ...

  5. [GXOI/GZOI2019]逼死强迫症

    题目 设我们最后的答案是\(g_n\) 我们发现在最后竖着放一个\(2\times 1\)的,和横着放两个\(1\times 2\)的就可以区分开之前的方案了 所以如果仅仅使用\(1\times 2\ ...

  6. 题解 洛谷 P5303 【[GXOI/GZOI2019]逼死强迫症】

    可以先去考虑没有\(1 \times 1\)的砖块的情况,对于最后一个位置只有两种情况,一个是竖着用一块砖铺设\(2 \times 1\),另一个为横着用两块砖铺设\(2 \times 2\). 设没 ...

  7. GXOI/GZOI2019题解

    GXOI/GZOI2019题解 P5300 [GXOI/GZOI2019]与或和 一眼题.. 显然枚举每个二进制位,答案就变成了全1子矩阵数量. 这个xjb推推,单调栈一下就行了. #include& ...

  8. 【LOJ】#3086. 「GXOI / GZOI2019」逼死强迫症

    LOJ#3086. 「GXOI / GZOI2019」逼死强迫症 这个就是设状态为\(S,j\)表示轮廓线为\(S\),然后用的1×1个数为j 列出矩阵转移 这样会算重两个边相邻的,只要算出斐波那契数 ...

  9. 「GXOI / GZOI2019」简要题解

    「GXOI / GZOI2019」简要题解 LOJ#3083. 「GXOI / GZOI2019」与或和 https://loj.ac/problem/3083 题意:求一个矩阵的所有子矩阵的与和 和 ...

随机推荐

  1. Oracle UNDO Tablespace size & Table Size

    Table Space Query select SEGMENT_NAME,bytes/1024/1024,a.* from dba_segments a UNDO Table Space Size ...

  2. poj 3683 Priest John's Busiest Day【2-SAT+tarjan+拓扑】

    转换成2-SAT模型,建边是如果时间(i,j)冲突就连边(i,j'),其他同理 tarjan缩点,判可行性 返图拓扑,输出方案 #include<iostream> #include< ...

  3. java 强大的反射机制

    这段时间,在对接一个开源的版本时,发现由于依赖的开源版本api老是随着版本的变化而变化,导致代码经常需要修改,异常痛苦. 终于,在一个风和日丽的下午(五月末的广州异常暴晒),楼主下定决心要修掉这个大篓 ...

  4. 黑客攻防技术宝典web实战篇:攻击用户·其他技巧习题

    猫宁!!! 参考链接:http://www.ituring.com.cn/book/885 随书答案. 1. 已知一项应用程序功能将一个查询字符串参数的内容插入到某个 HTTP 重定向的 Locati ...

  5. 如何通过Gitalk评论插件,5分钟为你的博客快速集成评论功能

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  6. iptables 使用总结

    Linux 系统的防火墙功能是由内核实现的 2.0 版内核中,包过滤机制是 ipfw,管理工具是 ipfwadm 2.2 版内核中,包过滤机制是 ipchain,管理工具是 ipchains 2.4 ...

  7. 微信小程序红包开发 小程序发红包 开发过程中遇到的坑 微信小程序红包接口的

    微信小程序红包开发 小程序发红包 开发过程中遇到的坑 微信小程序红包接口的   最近公司在开发一个小程序红包系统,客户抢到红包需要提现.也就是通过小程序来给用户发红包. 小程序如何来发红包呢?于是我想 ...

  8. Python 教程资源

    1.廖雪峰的官方网站 http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386 ...

  9. h5-17-元素拖放

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. h5-18-文件上传

    参考博客地址:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_Objects 参考博客地址:http: ...