JZOJ4787. 【NOIP2016提高A组模拟9.17】数格子

87 篇文章 0 订阅
8 篇文章 0 订阅

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

1 10000
3 10000
5 10000
0 0

Sample Output

1
11
95

Data Constraint

这里写图片描述

Hint

每个测试点数据组数不超过10组

分析

对30%的数据,是很简单的,可以打表,
但是从数据中找不到什么规律。

60%做法
我们先考虑,当前这个位置怎么铺对其他位置有什么影响?
如果是横着放,就与当前这一行有关;
如果是竖着放,就与下一行有关。

因为需要铺满的矩阵只有4×N,
所以我们考虑状压DP。
状压上一行对当前这一行的影响状态,
用1表示上一行是竖着放的,就是对现在这一行有影响,
0就相反。
不难想到一个的DP
但是转移比较慢,会超时。

100%做法
所以状态也就是仅仅只有16个,
也就是说,对于每一个I这一16个数,
DP的每一次转移就是通过旧的那16个数来造出新的16个数,
我们就联想到矩阵乘法。
一个1×16的矩阵×一个16×16的矩阵得到一个1×16的新矩阵。
之后就是快速幂。

code(c++)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h> 
#define _ %m
using namespace std;
struct note
{
    long long w[16];
};
long long jz[16][16]={
{1,0,0,1,0,0,0,0,0,1,0,0,1,0,0,1},
{0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
{0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
int n,m;
note ans;
long long s[16][16],t[16][16];
note times(note a)
{
    note c;
    memset(c.w,0,sizeof(c.w));
    for(int i=0;i<16;i++)
        for(int j=0;j<16;j++)
            c.w[i]=(c.w[i]+a.w[j]*s[i][j])_;
    return c;
}
int main()
{
    while(1)
    {
        scanf("%d %d",&n,&m);
        if((n==0)&&(m==0))break;
        memset(ans.w,0,sizeof(ans.w));
        memcpy(s,jz,sizeof(s));
        ans.w[0]=1;
        while(n)
        {
            if(n%2)ans=times(ans);
            n/=2;
            memset(t,0,sizeof(t));
            for(int i=0;i<16;i++)
                for(int j=0;j<16;j++)
                    for(int k=0;k<16;k++)
                        t[i][j]=(t[i][j]+s[i][k]*s[k][j])_;
            memcpy(s,t,sizeof(s));
        }
        printf("%lld\n",ans.w[0]);
    } 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值