【趣题】【矩阵乘法】NKOJ 1896 多米诺

来源:互联网 发布:黑白网络黑客教程 编辑:程序博客网 时间:2024/06/05 00:47

NKOJ 1896 多米诺
时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
用2x1的多米诺骨牌填满一个4xN(1 ≤ N ≤ 10^9) 的棋盘,总共有多少总方案。
结果可能很大,输出mod M((0 < M ≤ 10^5)的值。

输入格式
一行,两个整数N 和 M

输出格式
一行,一个整数表示结果。

样例输入
样例输入1:
3 10000
样例输入2:
5 10000

样例输出
样例输出1:
11
样例输出2:
95

思路:
设状态f[i]表示当n=i时的方案数,t[i]表示n=i时,不能拆成其他组合的方案数。
画图发现,t1=1,t2=5,t3=2,t4=3….即i>2时ti=i&1?2:3;
所以f[n]=sum(f[n-i]*t[i])+t[n] (i=1、2、3…..n-1)
令f[0]=0,则f[n]=sum(f[n-i]*t[i]) (i=1、2、3……n)
把特殊的ti分出来并分类讨论:
当n为奇数时,
f[n]=f[n-1]+4*f[n-2]+2 * (f[n-3]+f[n-5]+….+f[0])+3 *(f[n-4]+f[n-3]+….f[1]);
f[n+1]=f[n]+4*f[n-1]+2 * (f[n-2]+f[n-4]+….f[1])+3 *(f[n-3]+f[n-2]+….f[0]);
设p=f[n-3]+f[n-5]+….+f[0]; q=f[n-4]+f[n-3]+….f[1];

f[n]=f[n-1]+4*f[n-2]+2 * p+3 * q;
f[n+1]=f[n]+4*f[n-1]+2 * (p+f[n-2])+3 * p;
当n为偶数时,
f[n]=f[n-1]+4*f[n-2]+2 * (f[n-3]+f[n-5]+….+f[1])+3 *(f[n-4]+f[n-3]+….f[0]);
f[n+1]=f[n]+4*f[n-1]+2 * (f[n-2]+f[n-4]+….f[0])+3 *(f[n-3]+f[n-2]+….f[1]);
设p=f[n-3]+f[n-5]+….+f[1]; q=f[n-4]+f[n-3]+….f[0];

f[n]=f[n-1]+4*f[n-2]+2 * p+3 * q;
f[n+1]=f[n]+4*f[n-1]+2 * (p+f[n-2])+3 * p;
发现无论n为偶数或奇数,转移方程都一样…
所以构造F={f[n-1],f[n-2],p,q}* A=F`{f[n],f[n-1],p+f[n-2],p}={f[n-1]+4 * f[n-2]+2 * p+3 * q,f[n-1],p+f[n-2],p}
所以,A长:
1 1 0 0
4 0 1 0
2 0 0 1
3 0 1 0

代码:

#include<cstdio>#include<iostream>#include<cstring>using namespace std;#define ll long longconst int need=5;typedef int int_[need][need];int n,m,f[5];int_ a={{0},{0,1,1},{0,4,0,1},{0,2,0,0,1},{0,3,0,1}},ans,c;void matrix_multi(int_ a,int_ b){    memset(c,0,sizeof(c));    for(int i=1;i<=4;i++)     for(int j=1;j<=4;j++)      for(int k=1;k<=4;k++)       c[i][j]=((ll)a[i][k]*b[k][j]%m+c[i][j])%m;    memcpy(a,c,sizeof(c));}void matrix_power(int b){    for(int i=1;i<=4;i++) ans[i][i]=1;    while(b)    {        if(b&1) matrix_multi(ans,a);        b>>=1;        matrix_multi(a,a);      }}int main(){    scanf("%d%d",&n,&m);    f[0]=f[1]=1,f[2]=5,f[3]=11,f[4]=36;    if(n<=4)    {        printf("%d",f[n]);        return 0;    }    matrix_power(n-4);    int cnt=ans[1][1]*f[4]%m;    cnt=(cnt+ans[2][1]*f[3])%m;    cnt=(cnt+ans[3][1]*(f[2]+1))%m;    cnt=(cnt+ans[4][1])%m;    printf("%d",cnt);}
0 0
原创粉丝点击