【JZOJ4787】数格子

Description

这里写图片描述

Solution

状态压缩是没有疑问的。

那么我们对于一种状态,我们用1表示会影响到下一个,0表示不会。那么我们可以把每种状态能否转移到另一种状态,来构建一个转移矩阵。我们知道,矩阵乘法满足结合律,那么矩阵快速幂乘一下就可以了。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define ll long long
using namespace std;
int mo;
ll a[16];
bool pd[16]={1,0,0,1,0,0,0,0,0,1,0,0,1,0,0,1};
ll ys[16][16];
ll z[16][16];
ll b[16][16],c[16][16];
void mul(ll p[16][16],ll q[16][16])
{
    memset(c,0,sizeof(c));
    fo(i,0,15)
    fo(j,0,15)
    fo(k,0,15)
    c[i][j]=(c[i][j]+p[i][k]*q[k][j]%mo)%mo;
    memcpy(p,c,sizeof(c)); 
}
void pow(ll n)
{
    fo(i,0,15) b[i][i]=1;
    while(n)
    {
        if(n%2) mul(b,z);
        n/=2;
        mul(z,z);
    }
}
ll as[16];
int main()
{
    fo(i,0,15)
    fo(j,0,15)
    if(!(i&j) && pd[i|j]) ys[i][j]=1;
    while(1)
    {
        ll n;
        cin>>n>>mo;
        if(n==mo && !n) break;
        memset(a,0,sizeof(a));
        a[0]=1;
        memcpy(z,ys,sizeof(ys));
        memset(b,0,sizeof(a));
        memset(c,0,sizeof(a));
        memset(as,0,sizeof(as));
        pow(n);
        fo(j,0,15)
        fo(k,0,15)
        as[j]=(as[j]+a[k]*b[k][j]%mo)%mo;
        printf("%lld\n",as[0]);
    }
}
posted @ 2016-09-18 19:36  sadstone  阅读(44)  评论(0编辑  收藏  举报