【详●析】[GXOI/GZOI2019]逼死强迫症
【题目大意】
在\(2\times N\)的方格中用\(N-1\)块\(2\times 1\)的方砖和\(2\)块\(1\times 1\)的方砖填充,且两块\(1\times 1\)的方块不能有相邻的边,求合法方案数。
【分析】
啊,一道计数问题。反正我开始是这样想的。
如果没有那两块很碍事的砖,这不就是斐波拉契递推吗?,,,\(f[i]=f[i-1]+f[i-2]\),递推走起。
好,现在来看那两块碍事的砖。
首先,我们会发现,这两块特别的砖会把整个方格分成三个部分,我们假设左右两部分刚好是完整的(即是个矩形),那么中间的块就有性质了。
仔细推一推就会发现,当这两个特殊的块间隔奇数个块时,这两个块必定在相异的两行,并且中间只有一种方案构成。
同样的,当这两个特殊的块间隔偶数个块时,这两个块必定在相同的一行,并且中间也只有一种方案构成。
又因为不能有相邻的边,于是计算公式就出来了。
\]
细细理解下。
用这个大概只能得\(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]逼死强迫症的更多相关文章
- 【BZOJ5505】[GXOI/GZOI2019]逼死强迫症(矩阵快速幂)
[BZOJ5505][GXOI/GZOI2019]逼死强迫症(矩阵快速幂) 题面 BZOJ 洛谷 题解 如果没有那两个\(1*1\)的东西,答案就是斐波那契数,可以简单的用\(dp\)得到. 大概是设 ...
- [LOJ3086][GXOI/GZOI2019]逼死强迫症——递推+矩阵乘法
题目链接: [GXOI/GZOI2019]逼死强迫症 设$f[i][j]$表示前$i$列有$j$个$1*1$的格子的方案数,那么可以列出递推式子: $f[i][0]=f[i-1][0]+f[i-2][ ...
- P5303 [GXOI/GZOI2019]逼死强迫症
题目地址:P5303 [GXOI/GZOI2019]逼死强迫症 这里是官方题解 初步分析 从题目和数据范围很容易看出来这是一个递推 + 矩阵快速幂,那么主要问题在于递推的过程. 满足条件的答案一定是以 ...
- luogu P5303 [GXOI/GZOI2019]逼死强迫症
传送门 只有两行,考虑递推,设\(f_i\)为没有那两个\(1*1\)的,前\(i\)列的方案,可以发现一次可以放一个竖的或两个横的,也就是\(f_i=f_{i-1}+f_{i-2}\) 再设\(g_ ...
- [GXOI/GZOI2019]逼死强迫症
题目 设我们最后的答案是\(g_n\) 我们发现在最后竖着放一个\(2\times 1\)的,和横着放两个\(1\times 2\)的就可以区分开之前的方案了 所以如果仅仅使用\(1\times 2\ ...
- 题解 洛谷 P5303 【[GXOI/GZOI2019]逼死强迫症】
可以先去考虑没有\(1 \times 1\)的砖块的情况,对于最后一个位置只有两种情况,一个是竖着用一块砖铺设\(2 \times 1\),另一个为横着用两块砖铺设\(2 \times 2\). 设没 ...
- GXOI/GZOI2019题解
GXOI/GZOI2019题解 P5300 [GXOI/GZOI2019]与或和 一眼题.. 显然枚举每个二进制位,答案就变成了全1子矩阵数量. 这个xjb推推,单调栈一下就行了. #include& ...
- 【LOJ】#3086. 「GXOI / GZOI2019」逼死强迫症
LOJ#3086. 「GXOI / GZOI2019」逼死强迫症 这个就是设状态为\(S,j\)表示轮廓线为\(S\),然后用的1×1个数为j 列出矩阵转移 这样会算重两个边相邻的,只要算出斐波那契数 ...
- 「GXOI / GZOI2019」简要题解
「GXOI / GZOI2019」简要题解 LOJ#3083. 「GXOI / GZOI2019」与或和 https://loj.ac/problem/3083 题意:求一个矩阵的所有子矩阵的与和 和 ...
随机推荐
- ORACLE PL/SQL 实例精解之第六章 迭代控制之一
6.1 简单循环 简单循环,就想其名称一张,是一种最基本循环.简单循环具有如下结构 LOOP STATEMENT 1; STATEMENT 2; ... STATEMENT N; END LOOP; ...
- 洛谷 - P1141 - 01迷宫 - dfs
https://www.luogu.org/problemnew/show/P1141 能互相到达的格子的答案自然是一样的,第一次dfs标记联通块,第二次dfs把cnt传递到整个联通卡并顺手消除vis ...
- poj2186【利用强连通分量】
题意: 有n头奶牛,然后有个规则是A->B,B->C,那么A->C: A觉得B受欢迎,B觉得C受欢迎,那么A觉得C受欢迎: 求:被其他所有牛都欢迎的牛的数量: 思路: 原来的思路: ...
- hdu 1171 Big Event in HDU【生成函数】
按套路列生成函数式子然后暴力乘,这样复杂度看起来非常大,但是可以动态维护最大值,这样就是O(能过)的了 仔细想想这个多项式暴力乘理解成背包dp也行? #include<iostream> ...
- 【原创】《从0开始学Elasticsearch》—document的单/批量crud
内容目录 1.新建文档2.查询文档3.修改文档4.删除文档 1.新建文档 1). 语法1,手动指定document 的id: PUT /index_name/type_name/id{ &quo ...
- Oracle中dblink的创建与删除
查询数据库中有哪些dblink连接 select * from dba_objects where object_type='DATABASE LINK'; 删除公有的EMIS_PRODUCTOIN连 ...
- PowerDesigner 16.5的下载安装破解注册(图文详解)
http://blog.csdn.net/chenchunlin526/article/details/54707757
- [LOJ6041雅礼集训2017]事情的相似度
题解 \(SAM+set\)启发式合并+扫描线 首先可以发现题目要求的就是查询结尾在一段区间内的\(LCS\) 这个显然就是\(SAM\)的\(parent\)树上的\(step[LCA]\) 我们可 ...
- Eclipse Neon Java版本安装Java EE插件
Help→Install New Software 地址:Neon - http://download.eclipse.org/releases/neon/201703231000 选择 Web,X ...
- Invitation Cards POJ 1511 SPFA || dij + heap
http://poj.org/problem?id=1511 求解从1去其他顶点的最短距离之和. 加上其他顶点到1的最短距离之和. 边是单向的. 第一种很容易,直接一个最短路, 然后第二个,需要把边反 ...