看题n的数据,很明显告诉你了是矩阵乘法, 且矩阵阶数为2^m。
这里n要稍稍写一下高精度(减1, 除以2)。
用dp[i][j]表示前i层,最后层状态为j的合法个数。
很容易推出方程。
水水的题,速A
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; int n[103], m; const int N = 1<<5; int mod; int M; void add(int &a, int b) { a += b; if(a >= mod) a -= mod; } void mult(int a[N][N], int b[N][N]) { // 乘法函数 int c[N][N] = {0}; int i, j, k; for(k = 0; k < M; k++) for(i = 0; i < M; i++) for(j = 0; j < M; j++) add(c[i][j], a[i][k]*b[k][j] % mod); for(i = 0; i < M; i++) for(j = 0; j < M; j++) a[i][j] = c[i][j]; } int A[N][N]; bool ok(int a, int b) { // 判是否合法 int i; for(i = 0; i <m-1; i++) { int x = a&(1<<i), y = a&(1<<(i+1)); int u = b&(1<<i), v = b&(1<<(i+1)); if(x && y && u && v) return 0; if(!x && !y && !u && !v) return 0; } return 1; } void build() { // 建初始A矩阵 int i, j; for(i = 0; i < M; i++) for(j = 0; j < M; j++) A[i][j] = ok(i, j); } void div2(int *a) { // 除以2 int ans[103] = {0}; int i, res = 0; for(i = a[0]; i >= 0; i--) { ans[i] = (a[i]+res*10)/2; res = (a[i]+res*10)%2; } ans[0] = a[0]; if(ans[a[0]] == 0) ans[0]--; for(i = 0; i <= ans[0]; i++) a[i] = ans[i]; } void sub(int *a) { // 减1 int i; for(i = 1; i <= a[0]; i++) { a[i] --; if(a[i] < 0) a[i] += 10; else break; } if(a[a[0]] == 0) a[0]--; if(!a[0]) a[0]++; } char s[103]; int ans[N][N]; int main() { int i, j; scanf("%s%d%d", s, &m, &mod); n[0] = strlen(s); for(i = 1; i <= n[0]; i++) n[i] = s[n[0]-i]-'0'; for(i = 0; i < N; i++) for(j = 0; j < N; j++) ans[i][j] = (i==j); M = (1<<m); build(); sub(n); while(n[0]) { if(n[1]&1) mult(ans, A); mult(A, A); div2(n); } int sum = 0; for(i = 0; i < (1<<m); i++) for(j = 0; j < (1<<m); j++) add(sum, ans[i][j]); printf("%d\n", sum); return 0; }