做题感悟:做了这题感觉学习了不少东西,首先是关于状态压缩推公式学会了。
解题思路:
构造矩阵: B[ i ][ j ] (i , j 为状态,0 <= i ,j <= (1<<m) - 1 ) , 如果 B[ i ] [ j ] 等于 1 代表状态 i 与状态 j 相互兼容(i , j 可以在相邻两行),如果为 0 代表不可以相邻,还要有一个原始矩阵 A ,(1<<m)-1 行 ,1列的矩阵 ,代表第一行各种状态的方案数,这样 B * A 就得到了第二行各种状态的方案数,so ~ > A^( n - 1) * B 就得到了第 n 行的方案数,最后将最终矩阵相加就是总的方案数。因为这题指数比较大,so~>需要大数模拟除 2 的操作就可以了
代码:
#include<iostream>
#include<sstream>
#include<map>
#include<cmath>
#include<fstream>
#include<queue>
#include<vector>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<bitset>
#include<ctime>
#include<string>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std ;
#define INT long long int
#define L(x) (x * 2)
#define R(x) (x * 2 + 1)
const int INF = 0x3f3f3f3f ;
const double esp = 0.0000000001 ;
const double PI = acos(-1.0) ;
const int MY = 1400 + 5 ;
const int MX = 1005 + 5 ;
int S ,m ;
int d[MX] ;
INT mod ;
struct STR
{
int n ,d[MX] ;
STR()
{
n = 0 ;
memset(d ,0 ,sizeof(d)) ;
}
STR operator - (int x)
{
STR s ;
s.n = n ;
for(int i = n - 1 ;i >= 0 ; --i)
if(d[i])
{
d[i]-- ;
for(int j = i+1 ;j < n ; ++j)
d[j] = 9 ;
break ;
}
if(d[0] == 0)
{
for(int i = 1 ;i < n ; ++i)
s.d[i-1] = d[i] ;
s.n-- ;
}
else
for(int i = 0 ;i < n ; ++i)
s.d[i] = d[i] ;
return s ;
}
STR operator >> (int x)
{
STR s ;
int a[MX] ,num = 0 ,sum = 0 ;
for(int i = 0 ;i < n ; ++i)
{
sum = sum*10 + d[i] ;
if(sum >= 2)
{
a[num++] = sum / 2 ;
sum = sum%2 ;
}
else if(num)
a[num++] = 0 ;
}
for(int i = 0 ;i < num ; ++i)
s.d[i] = a[i] ;
s.n = num ;
return s ;
}
bool operator &(int x)
{
if(d[n-1]&1) return true ;
return false ;
}
} ;
struct M
{
INT p[33][33] ;
M()
{
memset(p ,0 ,sizeof(p)) ;
}
void init()
{
for(int i = 0 ;i < S ; ++i)
p[i][i] = 1 ;
}
} ;
bool judge(int x ,int y)
{
for(int i = 0 ;i < m-1 ; ++i)
if(((x&(1<<i)) && (x&(1<<(i+1))) && (y&(1<<i)) && (y&(1<<(i+1))))||
(!(x&(1<<i)) && !(x&(1<<(i+1))) && !(y&(1<<i)) && !(y&(1<<(i+1)))))
return false ;
return true ;
}
M Pre() // 构造矩阵
{
M c ;
for(int i = 0 ;i < S ; ++i)
for(int j = i ;j < S ; ++j)
if(judge(i ,j))
c.p[i][j] = c.p[j][i] = 1 ;
return c ;
}
M operator * (const M& a ,const M& b) // 矩阵乘法
{
M c ;
for(int i = 0 ;i < S ; ++i)
for(int k = 0 ;k < S ; ++k)
if(a.p[i][k])
for(int j = 0 ;j < S ; ++j)
c.p[i][j] = (c.p[i][j] + a.p[i][k]*b.p[k][j]) %mod ;
return c ;
}
M pow(M a ,STR k) // 快速幂
{
M b ;
b.init() ;
while(k.n)
{
if(k&1)
b = b * a ;
a = a * a ;
k = k>>1 ;
}
return b ;
}
int main()
{
char str[MX] ;
while(cin>>str>>m>>mod)
{
S = (1<<m) ; // 总状态
STR s ;
for(int i = 0 ;i < strlen(str) ; ++i)
s.d[i] = str[i]-'0' ;
s.n = strlen(str) ;
s = s - 1 ;
M c = Pre() ;
M b = pow(c ,s) ;
INT ans = 0 ;
for(int i = 0 ;i < S ; ++i)
for(int j = 0 ;j < S ; ++j)
ans = (ans + b.p[i][j]) %mod ;
cout<<ans<<endl ;
}
return 0 ;
}