【BZOJ2004】[HNOI2010]Bus 公交线路

【BZOJ2004】[HNOI2010]Bus 公交线路

题面

bzoj

洛谷

题解

$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; 
} 
posted @ 2019-01-05 21:06  heyujun  阅读(248)  评论(0编辑  收藏  举报