【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;
}