POj 3420
强行一道矩阵递推, 强行暴力矩阵水过
题目好懂就不说了, 其实我们可以先打一个暴力, 愉快地打完, 就是枚举i-1行的状态, 判断从这个状态可以使第i行的那些状态被更新, 然后就可以去想矩阵了, 那么很好想暴力一个16*16的矩阵直接弄好每个状态可以对应的更新, 然后自乘n次最右下角的元素就是答案了, 由于我这个题一开始想到的就是状压, 听说可以优化成4*4的矩阵, 那么就留给读者自己去想了, 其实我也不会, 手动滑稽。。。
#include <cstdio>
#include <cstring>
typedef long long LL;
const int P = 16;
const LL d[P][P] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1};
#define rep(i, s, t) for(int i = s; i <= t; ++i)
namespace Galaxy {
int Mod, n;
struct Matrix {
LL x[P][P];
Matrix() {memset(x, 0, sizeof x);}
}Ans, Tmp, unit;
Matrix operator * (Matrix a, Matrix b) {
rep(i, 0, 15)rep(j, 0, 15) Ans.x[i][j] = 0;
rep(i, 0, 15)
rep(j, 0, 15)
rep(k, 0, 15)
Ans.x[i][j] = (Ans.x[i][j]+a.x[i][k] * b.x[k][j] % Mod) % Mod;
return Ans;
}
Matrix operator ^ (Matrix a, int b) {
Tmp = a;
for(; b; b >>= 1, a = a*a)
if(b & 1) Tmp = Tmp * a;
return Tmp;
}
void solve() {
while(scanf("%d%d", &n, &Mod) == 2 && n + Mod) {
memcpy(unit.x, d, sizeof d);
unit = unit ^ (n-1);
printf("%lld\n", unit.x[15][15] % Mod);
}
}
};
int main() {
Galaxy :: solve();
return 0;
}