【BZOJ2004】[HNOI2010]Bus 公交線路
阿新 • • 發佈:2019-01-05
【BZOJ2004】[HNOI2010]Bus 公交線路
題面
題解
\(N\)特別大\(P,K\)特別小,一看就是矩陣快速冪+狀壓
設\(f[S]\)表示公交車狀態為\(S\)的方案數
這是什麼意思啊啊啊?
其實就是表示一個位置是否是公交車最後停靠的位置的狀態
剔除無效狀態後大約只有\(125\)左右的狀態
直接存矩陣裡快速冪轉移就好了
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define Mod 30031 #define RG register int SIZE; struct Matrix { int a[135][135]; Matrix() { clear(); } inline void clear() { memset(a, 0, sizeof(a)); } void init() { clear(); for (int i = 0; i < SIZE; i++) a[i][i] = 1; } inline void add(int &x, int y) { x += y; if (x >= Mod) x -= Mod; } inline int *operator [] (int id) { return a[id]; } inline Matrix operator * (const Matrix &b) { Matrix c; for (RG int i = 0; i < SIZE; i++) for (RG int j = 0; j < SIZE; j++) for (RG int k = 0; k < SIZE; k++) add(c[i][k], a[i][j] * b.a[j][k] % Mod); return c; } } S; int N, P, K; int w[1 << 12], v[1 << 12]; Matrix fpow (Matrix x, int y) { Matrix res; res.init(); while (y) { if (y & 1) res = res * x; x = x * x; y >>= 1; } return res; } int main () { scanf("%d%d%d", &N, &K, &P); for (int i = 1; i < (1 << P); i++) { int res = 0, x = i; while (x) ++res, x -= x & (-x); if (res == K && (i & (1 << P - 1))) w[i] = ++SIZE, v[SIZE] = i; } for (int i = 1; i <= SIZE; i++) { if (v[i] & 1) S[i - 1][w[(1 << P - 1) | (v[i] >> 1)] - 1] = 1; else { for (int j = 0; j < P; j++) if (v[i] & (1 << j)) S[i - 1][w[(1 << P - 1) | ((v[i] ^ (1 << j)) >> 1)] - 1] = 1; } } S = fpow(S, N - K); int i = w[(1 << P) - (1 << (P - K))]; printf("%d\n", S[i - 1][i - 1]); return 0; }