这道题非常综合,和上一道题很类似,这道题,也是铺地砖问题,
只不过 地面变成了 4*n 同时需要输入 mod ,结果对 mod 取模。。
那么有了上一题的经验。
我们开始整理一下 b [ n ] 代表 4*n 的不可分割矩阵种类个数。。。
首先 b[ 1 ] = 1 ,
b [ 2 ] = 4 ,之后我们发现了一个类似的规律,我们所谓之不可分割矩阵,要求的就是每一行之间都存在一个连接的木板。。,同行之间是无所谓的,但是不同行之间都需要一块木板进行连接,才能保证 这两行合在了一起,成了不可分割的一部分
我们简单的画一下,发现 n >= 3 之后 有了一定的规律, 每个不可分割的模板花纹看上去都几乎一样,(这里可以自己画一下看看)
然后神奇的事情出现了,我们发现了这样一个规律:(n >= 3)
b [ n ] = 2 (n 为奇数 ) ;
b [ n ] = 3 (n为偶数) ;
那么 a [ n ] = a [ n - 1 ] * b [ 1 ] + a [ n - 2 ] * b [ 2 ] ....... + a [ 0 ] * b [ n ];
但是如果这样还不够简便,我们可以退出 a [ n - 1 ] 表达式
a [ n - 1 ] = a [ n - 2 ] * b [ 1 ] + ....... a [ 0 ] * b [ n - 1 ]
然后 a [ n - 1 ] 带回 同时 把 b [ n ] 具体数字代入
a [ n ] = 5 * a [ n - 2 ] + 6 * a [ n - 3 ] + 5 * ( a [ n - 4 ] + a [ n - 5 ] ....... a [ 0 ] )
但是这样的话,,后边还会存在一堆数字, 这道题 n <= 1e9 所以这样跑下去还是不够快速
由上式 我们还可以 推出
a [ n - 1 ] = 5 * a [ n - 3 ] + 6 * a [ n - 4 ] ........
那么我们惊讶的发现,如果两式相减,我们可以消去一大部分累赘的式子
那么就可知
a [ n ] = a [ n - 1 ] + 5 * a [ n - 2 ] + a [ n - 3 ] - a [ n - 4 ];
有了这个式子,我们就很好处理了,但是依旧避免不了需要 一个循环跑一次,还是不够优秀
那么 我们脑洞大开,联想一下之前那个巨大数据范围的斐波那契数列
如果这里我们用一下之前学过的矩阵来优化 不就可以更加便捷了吗 ?
那么开始构造矩阵, 基础矩阵的话
就是 而我们构造的矩阵不就是 就会推出
所以最终 输出 A [ 3 ] [ 0 ] 就好了
以下是矩阵的模板 可以使用一下,可以自己设置行和列
struct Matrix
{
int n,m;
int a[MAXN][MAXM];
void clears()
{
n=m=0;
memset(a,0,sizeof(a));
}
Matrix operator *(const Matrix &b)
{
Matrix tmp;
tmp.clears();
tmp.n=n;
tmp.m=b.m;
for(int i=0; i<n; ++i)
for(int j=0; j<b.m; j++)
for(int k=0; k<m; k++)
{
tmp.a[i][j] += a[i][k]*b.a[k][j];
tmp.a[i][j] %= mod;
}
return tmp;
}
};
还有矩阵快速幂的模板
Matrix pow_(Matrix t,int x)
{
Matrix E;
E.clears();
E.n=E.m=t.n;
for(int i=0; i<t.n; i++)
{
E.a[i][i]=1;
}
if(x==0)return E;
while(x)
{
if(x&1)
E = E * t;
t = t * t;
x >>= 1;
}
return E;
}
有了这些模板,我们套用一下 就可以解决这个问题了。。。
(矩阵快速幂可以帮我们把正常的加法递推运算优化)
以下为 AC 代码
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=10;
const int MAXM=10;
int r,mod;
struct Matrix
{
int n,m;
int a[MAXN][MAXM];
void clears()
{
n=m=0;
memset(a,0,sizeof(a));
}
Matrix operator *(const Matrix &b)
{
Matrix tmp;
tmp.clears();
tmp.n=n;
tmp.m=b.m;
for(int i=0; i<n; ++i)
for(int j=0; j<b.m; j++)
for(int k=0; k<m; k++)
{
tmp.a[i][j] += a[i][k]*b.a[k][j];
tmp.a[i][j] %= mod;
}
return tmp;
}
};
Matrix pow_(Matrix t,int x)
{
Matrix E;
E.clears();
E.n=E.m=t.n;
for(int i=0; i<t.n; i++)
{
E.a[i][i]=1;
}
if(x==0)return E;
while(x)
{
if(x&1)
E = E * t;
t = t * t;
x >>= 1;
}
return E;
}
int main()
{
while(~scanf("%d %d",&r,&mod)&&r&&mod)
{
int a[]= {1,1,5,11};
if(r<=3)
{
printf("%d\n",a[r]%mod);
continue;
}
Matrix A;
A.clears();
A.n=A.m=4;
A.a[0][1]=A.a[1][2]=A.a[2][3]=1;
A.a[3][0]=-1; A.a[3][1]=1; A.a[3][2]=5; A.a[3][3]=1;
Matrix temp;
temp = pow_(A, r-3);
Matrix x;
x.clears();
x.n=4;
x.m=1;
x.a[0][0]=1;
x.a[1][0]=1;
x.a[2][0]=5;
x.a[3][0]=11;
x = temp*x;
printf("%d\n",(x.a[3][0]+mod)%mod);
}
return 0;
}