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]);
}
}