算法:
1.状态压缩
2.搜索
3.矩阵快速幂
View Code
#include<iostream> using namespace std; typedef long long LL; const int mod = 1000000007; const int mask = 255; struct Matrix{ LL mat[100][100]; void unit(){ memset(mat,0,sizeof(mat)); for(int i = 0; i < 100; i++) mat[i][i]=1; } void zero(){ memset(mat,0,sizeof(mat)); } }T,A,U; Matrix operator * (const Matrix &a,const Matrix &b){ Matrix tmp; tmp.zero(); for(int i = 0; i <= 70; i++){ for(int k = 0; k <= 70; k++){ if(!a.mat[i][k]) continue; for(int j = 0; j <= 70; j++){ tmp.mat[i][j] += (a.mat[i][k]*b.mat[k][j])%mod; tmp.mat[i][j] %= mod; } } } return tmp; } Matrix operator ^(Matrix x,int k){ Matrix tmp; tmp.unit(); while(k){ if(k&1) tmp = tmp*x; x = x*x; k = (k>>1); } return tmp; } Matrix Pow(Matrix x,int k){ if(k == 0) return U; if(k&1) return (Pow(x,k/2)*Pow(x,k/2)*x); else return (Pow(x,k/2)*(Pow(x,k/2))); } int vis[mask+10],id[mask+10],legal[mask+10],idx; /* 判断横放是否合法 0 1 2 7 3 6 5 4 只要判断01234567,65432170是否有两个连续1 */ bool check(int x){ int y=0,t = x>>1; for(int i = 0; i < 7; i++){ y = (y<<1) | (t&1); t >>= 1; } y = (y<<1) | (x&1); bool flag = true; for(int i = 0; i < 8; i++){ if( !( x&(1<<i) ) ) continue; if( i == 7 || !( x&(1<<(i+1))) ){ flag = false; break; } i++; } if(flag) return true; flag = true; for(int i = 0; i < 8; i++){ if( !( y&(1<<i) ) ) continue; if( i == 7 || !( y&(1<<(i+1)) ) ){ flag = false; break; } i++; } return flag; } /* 搜索出合法状态,并且再把状态压缩。。 */ void DFS(int x){ if( vis[x] ) return; vis[x] = 1; int c = ~x & mask; if( id[x] == -1 ) id[x] = idx++; for(int i = 0; i <= mask; i++){ if( (i&c)==c && check( i&x ) ){ if( id[i] == -1 ) id[i] = idx++; T.mat[ id[i] ][ id[x] ] = 1; if( !vis[i] ) DFS(i); } } } void init(){ T.zero(); U.unit(); memset(vis,0,sizeof(vis)); memset(id,0xff,sizeof(id)); idx = 0; DFS(mask); T.mat[0][0]+=1; memset(legal,0,sizeof(legal)); for(int i = 0; i <= mask; i++){ if( ~id[i] && T.mat[id[i]][0] ) legal[ id[i] ] = 1; } legal[0] += 1; } void solve(int k){ A = T^(k-1); LL res = 0; for(int i = 0; i < idx; i++){ res = (res+legal[i]*A.mat[i][0]%mod)%mod; } printf("%I64d\n", res); } int main(){ //freopen("1002.in","r",stdin); //freopen("1.out","w",stdout); init(); int t, k; scanf("%d", &t); for(int ncase = 1; ncase <= t; ncase++){ scanf("%d",&k); printf("Case %d: ", ncase); solve(k); } }