向前走莫回头❤

【POJ 3420】Quad Tiling(dp|递推 +矩阵快速幂)

**

Quad Tiling

**
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4122 Accepted: 1885

Description
Tired of the Tri Tiling game finally, Michael turns to a more challengeable game, Quad Tiling:
In how many ways can you tile a 4 × N (1 ≤ N ≤ 109) rectangle with 2 × 1 dominoes? For the answer would be very big, output the answer modulo M (0 < M ≤ 105).

Input
Input consists of several test cases followed by a line containing double 0. Each test case consists of two integers, N and M, respectively.

Output
For each test case, output the answer modules M.

Sample Input
1 10000
3 10000
5 10000
0 0

Sample Output
1
11
95

Source
POJ Monthly–2007.10.06, Dagger

【题解】【递推+矩阵快速幂】
【刚开始,推式子ing….一段漫长而依赖std的时光】
【result : f[i]=f[i-1]+5*f[i-2]+f[i-3]-f[i-4]】
【具体这个式子是如何得来的?呵呵,我可不可以说我是凑的?!(我刚开始用f[1]、f[2]凑f[3],然后发现f[4]不满足,failed! 然后,用f[1]、f[2]、f[3]凑f[4],然后,f[5]不满足,failed!然后,我用前四个凑f[5],往后试了几个,发现accept!)】
【好了,朴素的算法已经得出,那么,构造矩阵即可】
初始矩阵为: {f[4],f[3],f[2],f[1]} => {36,11,5,1}
转移矩阵为:

1100501010011000

【注意:转移矩阵在进行快速幂时,需要%m,但由于有负数需要+m%m】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
    long long k[5][5];
}d;
int f[5],n,m,ans;
inline node jc(node a,node b)
{
    node c;
    memset(c.k,0,sizeof(c.k));
    for(int i=1;i<=4;++i)
     for(int j=1;j<=4;++j)
      for(int l=1;l<=4;++l)
       {
          long long sm=a.k[i][l]*b.k[l][j];
          sm=((sm+m)%m+m)%m;
          c.k[i][j]=(c.k[i][j]+sm)%m;
       }
    return c;
}
node poww(node x,int p)
{
    if(p==1) return d;
    if(p%2==0)
     {
        node a=poww(x,p/2);
        a=jc(a,a);
        return a;
     }
    else
     {
        node a=poww(x,p/2);
        a=jc(a,a);
        a=jc(a,x);
        return a;
     }
}
inline int solve(int p)
{
    node as=poww(d,p);
    int sum[5];
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=4;++i)
     for(int j=1;j<=4;++j)
      sum[j]=(sum[j]+as.k[i][j]*f[i]%m)%m;
    return sum[1];
}
int main()
{
    //freopen("int.txt","r",stdin);
    //freopen("my.txt","w",stdout);
    f[1]=36; f[2]=11; f[3]=5; f[4]=1;
    d.k[1][1]=d.k[1][2]=d.k[2][3]=d.k[3][1]=d.k[3][4]=1;
    d.k[2][1]=5; d.k[4][1]=-1;
    while((scanf("%d%d",&n,&m)==2)&&!(n==0&&m==0))
     {
        if(n==1||n==2||n==3||n==4) {printf("%d\n",f[4-n+1]%m); continue;}
        ans=solve(n-4);
        printf("%d\n",ans);
     }
}
posted @ 2016-10-27 20:48  lris0-0  阅读(73)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m