题目链接:http://poj.org/problem?id=3420
题目思路:状态压缩+矩阵二分幂,一般解法是构造16*16的转移矩阵,也有一种是去掉无用状态,只剩下5个有用状态的5*5转移矩阵。还有一种方法是推组合学公式。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<algorithm> #include<vector> #include<stack> #include<list> #include<iostream> #include<map> using namespace std; #define inf 0x3f3f3f3f #define Max 110 int max(int a,int b) { return a>b?a:b; } int min(int a,int b) { return a<b?a:b; } int cnt=16,mod,n,m=4; int c[17][17]; int mp[17][17]; void dfs(int pos,int ps,int s) { if(pos==m) { mp[ps][s]=1; return; } if(pos+2<=m&&(s&(1<<(pos+1)))==0&&(s&(1<<pos))==0) dfs(pos+2,ps,s|(1<<(pos))|(1<<(pos+1))); dfs(pos+1,ps,s); } void mul(int a[][17],int b[][17]) { int i,j; memset(c,0,sizeof(c)); for(i=0;i<cnt;i++) for(j=0;j<cnt;j++) { for(int k=0;k<cnt;k++) { c[i][j]=(c[i][j]+(__int64)a[i][k]*b[k][j])%mod; } } for(i=0;i<cnt;i++) for(j=0;j<cnt;j++) a[i][j]=c[i][j]; // if(n==1) } int cal() { int i,j; if(n==1) return 1; int a[17][17],b[17][17]; for(i=0;i<cnt;i++) for(j=0;j<cnt;j++) { a[i][j]=mp[i][j]; b[i][j]=mp[i][j]; } n--; while(n) { if(n%2==1) mul(a,b); mul(b,b); n=n>>1; } return a[15][15]; } int main() { int i,j; for(i=0;i<cnt;i++) dfs(0,i,~i&15); while(scanf("%d%d",&n,&mod),n|mod) { printf("%d\n",cal()%mod); } }