【poj3420】递推式转矩阵乘法

历史性的时刻!!!

推了一晚上!和hyc一起萌萌哒地推出来了!!

被摧残蹂躏的智商啊!!!

然而炒鸡高兴!!

(请不要介意蒟蒻的内心独白。。)

设a[i]为扫到第i行时的方案数。

易知,对于一行1*4的格子,只有一种方案把它铺满。

首先,对于当前的第i行,如果它不和第i-1行有联系(也就是它是独立的一行),那么就有1*a[i-1]=a[i-1]种方案。

如果第i行和第i-1行有联系(2行间互相联系),那么共有一下四种方案:

如果第i行、第i-1行、第i-2行都有联系(3行间两两联系),那么共有两种方案(此图以及的轴对称图形):

如果第i行、第i-1行、第i-2行、第i-3行都有联系(4行间两两联系),那么共有三种方案(上面两种方案加下面一种):

……

一直递推下去,我们可以发现:

2行间相互联系 --> 4种方案

3行间相互联系 --> 2种方案

4行间相互联系 --> 3种方案

……

奇数行相互联系(n>2) --> 2种方案

偶数行相互联系(n>2) --> 3种方案

所以,我们可以得出:

a[i]=a[i-1]+4*a[i-2]+2*(a[i-3]+a[i-5]+……+a[(i&1)?0:1])+3*(a[i-4]+a[i-6]+……+a[(i&1)?1:0]);

设s=a[i-3]+a[i-5]+……+a[(i&1)?0:1],t=a[i-4]+a[i-6]+……+a[(i&1)?1:0];

该递推式可以转化为矩阵乘法:

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

const int N=1000000010;
int Mod;
struct node{
    int s[5][5];
    int sx,sy;
};

node mult(node a,node b)
{
    node t;
    t.sx=a.sx;t.sy=b.sy;
    memset(t.s,0,sizeof(t.s));
    for(int i=1;i<=a.sx;i++)
        for(int j=1;j<=b.sy;j++)
            for(int k=1;k<=a.sx;k++)
            {
                t.s[i][j]+=(a.s[i][k]*b.s[k][j])%Mod;
                t.s[i][j]%=Mod;
            }
    return t;
}

void quickpow(int n)
{
    if(n==0) {printf("0
");return ;}
    node a;
    a.s[1][1]=1%Mod,a.s[1][2]=4%Mod,a.s[1][3]=2%Mod,a.s[1][4]=3%Mod;
    a.s[2][1]=1%Mod,a.s[2][2]=0%Mod,a.s[2][3]=0%Mod,a.s[2][4]=0%Mod;
    a.s[3][1]=0%Mod,a.s[3][2]=1%Mod,a.s[3][3]=0%Mod,a.s[3][4]=1%Mod;
    a.s[4][1]=0%Mod,a.s[4][2]=0%Mod,a.s[4][3]=1%Mod,a.s[4][4]=0%Mod;
    a.sx=4;a.sy=4;
    node b;
    b.s[1][1]=b.s[2][2]=b.s[3][3]=b.s[4][4]=1%Mod;
    b.s[1][2]=b.s[1][3]=b.s[1][4]=0%Mod;
    b.s[2][1]=b.s[2][3]=b.s[2][4]=0%Mod;
    b.s[3][1]=b.s[3][2]=b.s[3][4]=0%Mod;
    b.s[4][1]=b.s[4][2]=b.s[4][3]=0%Mod;
    b.sx=4;b.sy=4;
    while(n)
    {
        if(n&1) b = mult(a,b);
        a = mult(a,a);
        n>>=1;
    }
    node c;
    c.sx=4;c.sy=1;
    c.s[1][1]=1%Mod;c.s[2][1]=c.s[3][1]=c.s[4][1]=0%Mod;
    c = mult(b,c);
    printf("%d
",c.s[1][1]);
    return ;
}

int main()
{
    while(1)
    {
        int x;
        scanf("%d%d",&x,&Mod);
        if(x==0) return 0;
        quickpow(x);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/KonjakJuruo/p/4845116.html