Problem
Description
Input
Output
Sample Input
1 10000
3 10000
5 10000
0 0
Sample Output
1
11
95
Data Constraint
每个测试点数据组数不超过10组
Solution
我们看到
N≤109
,所以我们要用矩阵乘法。
我们可以建立一个16*16的矩阵,分别记录状态i转到状态j的可行性(OK就是1,不OK就是0,i,j均为二进制数)。
那么我们可以设x=i or j。那么x拆成4位二进制数后,我们看看有没有连续奇数个0,这样的话i不能转到j。
然后这个矩阵n-1次方后的矩阵的0,0即为答案。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define LL long long
using namespace std;
int n,m,i,j,k;
LL a[16][16],b[16][16],c[16][16],d[16][16],g[16][16],ans;
int pd(int x)
{
int rs=0,s=1;
while (s<16)
{
if ((x&s)==0) rs++;else
{
if (rs%2) return 0;
rs=0;
}
s*=2;
}
if (rs%2) return 0;
return 1;
}
void pre()
{
int i,j,k;
fo(i,0,15)
fo(j,0,15)
if ((i&j)==0) a[i][j]=pd(i|j);
memset(b,0,sizeof(b));
fo(k,0,15)
fo(i,0,15)
fo(j,0,15)
b[i][j]+=a[i][k]*a[k][j];
}
void ksm(int x)
{
int i,j,k,p=x;
memcpy(g,a,sizeof(a));
memcpy(c,a,sizeof(a));
while (p)
{
if (p%2==1)
{
memset(d,0,sizeof(d));
fo(k,0,15)
fo(i,0,15)
fo(j,0,15)
d[i][j]=(d[i][j]+g[i][k]*c[k][j])%m;
memcpy(g,d,sizeof(d));
}
memset(d,0,sizeof(d));
fo(k,0,15)
fo(i,0,15)
fo(j,0,15)
d[i][j]=(d[i][j]+c[i][k]*c[k][j])%m;
memcpy(c,d,sizeof(d));
p/=2;
}
}
int main()
{
pre();
while (1)
{
scanf("%d%d",&n,&m);
if (n==0 && m==0) break;
ksm(n-1);
ans=g[0][0];
printf("%lld\n",ans);
}
}