做题感悟:做了这题感觉学习了不少东西,首先是关于状态压缩推公式学会了。
解题思路:
构造矩阵: 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 ; }
时间: 2024-10-05 16:27:10