SCU 4430 lovd_kd's_room (动态规划+矩阵优化)

题目链接

4430: lovd_kd's_room

Submit your solution     Discuss this problem     Best solutions

Time Limit: 1000ms

Description

Love_kd and mrxy56 are having a quarrel about how to decorate their marriage room. As we all know, they are both fantastic programmers,so they bought a fantastic marriage room. The room is four_grid wide and n_grid long . They have only one kind of floor tile which is 1*2. But they don't know how to tile it.So they decide find all the ways which can tile the floor and which is the best one.(because of the large answer, please output the answer modulo M).

Input

The first line is a integer k represent this question has k test cases.Each test case consists of two integers, N (1<=N<=10^9)and M (0<M<=10^5), respectively.

Output

For each test case, output the answer modules M .

Sample Input

3
1 10000
2 10000
5 10000

Sample Output

1
5
95

Author

laobi 

题意:4*n的矩形,用1*2的矩形来填,问有多少种方式可以将其填满?

题解:容易想到状压dp。用dp[i][j] 表示前i-1行已经填满,第 i 的填的状态为 j 的方案数。由于n的范围很大,所以要用到矩阵优化。

这里有一个知识点:如果一个图用一个n*n的矩阵表示,a[i][j] 表示点i到点j的边数。那么这个矩阵求x幂后,a[i][j]表示从点i到点j ,经过x条边有多少种走法?

所以这里我们根据转移方程,建一个16*16的矩阵,如果i状态能转移到j状态则a[i][j]=1。那么对于这个矩阵求n次幂后,a[15][15]就是最后的答案。

代码如下:

#include<cstdio>
#include<cstring>
#include<set>
#include<iostream>
#include<map>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<cctype>
#include<algorithm>
#define inf 0x3fffffff
#define nn 1100
#define mod 1000000007
typedef long long LL;
using namespace std;
int n,m;
struct Matrix
{
    LL a[20][20];
    int n1,n2;
    void init()
    {
        n1=n2=16;
        memset(a,0,sizeof(a));
    }
    Matrix operator * (const Matrix &b)const
    {
        Matrix tmp;
        tmp.init();
        tmp.n1=n1,tmp.n2=b.n2;
        for(int i=0;i<n1;i++)
        {
            for(int j=0;j<b.n2;j++)
            {
                for(int k=0;k<n2;k++)
                {
                    tmp.a[i][j]+=a[i][k]*b.a[k][j];
                    tmp.a[i][j]%=m;
                }
            }
        }
        return tmp;
    }
}dw,tem,ans;
void init()
{
    dw.init();
    int i,j,k;
    for(i=0;i<16;i++)
    {
        for(j=0;j<16;j++)
        {
            dw.a[i][j]=i==j?1:0;
        }
    }
    tem.init();
    int ix;
    for(i=0;i<16;i++)
    {
        for(j=0;j<16;j++)
        {
            if((i^j)==15)
            {
                tem.a[i][j]=1;
            }
            else
            {
                if((i|j)==15)
                {
                    ix=i&j;
                    for(k=0;k<4;k++)
                    {
                        if((1<<k)&ix)
                        {
                            if((1<<(k+1)&ix))
                            {
                                k++;
                            }
                            else
                                break;
                        }
                    }
                    if(k>=4)
                    {
                        tem.a[i][j]=1;
                    }
                }
            }
        }
    }
}
Matrix po(Matrix x,int y)
{
    Matrix re=dw;
    while(y)
    {
        if(y%2)
        {
            re=re*x;;
        }
        x=x*x;
        y/=2;
    }
    return re;
}
int main()
{
    int t;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        ans=po(tem,n);
        printf("%lld\n",ans.a[15][15]);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值