• [HNOI 2010]Bus 公交线路


    Description

    题库链接

    (N) 个车站, (K) 条公交线路。第 (1)(K) 站是这 (K) 线路的起点站。第 (N-K+1)(N) 是终点站。车只会从编号小的车站驶向编号大的车站。

    要求每个车站恰好只属于一个线路,而且同一个线路相临两站距离不得大于 (P) 。求有多少种安排方法。输出答案对 (30031) 取余数。

    (1leq Nleq 10^9,1<Kleq Pleq 10,K<N)

    Solution

    不妨抛开前 (K) 个车站不看。

    我们发现,只要每连续的 (P) 个站中,都出现了所有 (K) 种公交车,方案就是合法的。

    证明:
    如果方案不合法,必有一线路有相邻站距离大于 (P) ,即这连续 (P) 个站中缺少一种公交车。根据逆否命题等价,得证。

    由于没有线路车站数的限制, (P) 又不大,容易想到状态压缩动态规划:

    (F_{i,S}) 表示:前 (i) 位已经确定完毕,不同公交车最后经停站距 (i+1) 的位置的状态为 (S) ,此时的方案总数。

    由于公交车是无差别的, (S) 实际上是 (K) 个不同整数的集合。每个元素都是 (1)(P) 的数。

    更进一步,集合 (S) 中一定有一个元素 (1) ,其余的都是 (2)(P)

    所以最大只有 (C_{P-1}^{K-1}) 个状态即 (C_9^5=126) 这样一来我们容易想到用矩阵乘法来优化递推。

    Code

    //It is made by Awson on 2018.3.12
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int yzh = 30031, SIZE = (1<<10);
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, k, p, bin[20], cnt, sta[130], fin, mp[1050];
    struct mat {
        int a[130][130];
        mat() {memset(a, 0, sizeof(a)); }
        mat(int _a[130][130]) {for (int i = 1; i <= 126; i++) for (int j = 1; j <= 126; j++) a[i][j] = _a[i][j]; }
        mat operator * (const mat &b) const {
        mat ans;
        for (int i = 1; i <= cnt; i++)
            for (int j = 1; j <= cnt; j++)
            for (int k = 1; k <= cnt ; k++)
                ans.a[i][j] = (ans.a[i][j]+1ll*a[i][k]*b.a[k][j]%yzh)%yzh;
        return ans;
        }
    }S, T;
    
    mat quick_pow(mat a, int b) {
        mat ans = a; b--;
        while (b) {
        if (b&1) ans = ans*a;
        a = a*a, b >>= 1;
        }
        return ans;
    }
    int bitcount(int x) {int ans = 0; while (x) x -= lowbit(x), ++ans; return ans; }
    void work() {
        read(n), read(k), read(p); bin[0] = 1; for (int i = 1; i < 20; i++) bin[i] = (bin[i-1]<<1);
        for (int i = 0; i < bin[p-1]; i++) if (bitcount(i) == k-1) sta[++cnt] = (i<<1|1), mp[i<<1|1] = cnt;
        for (int i = 1; i <= cnt; i++) {
        if (sta[i] == bin[k]-1) S.a[i][i] = 1, fin = i;
        int t = sta[i];
        if (t&bin[p-1]) T.a[i][mp[(t-bin[p-1])<<1|1]] = 1;
        else for (int x = t; x; x -= lowbit(x)) T.a[i][mp[(t-lowbit(x))<<1|1]] = 1;
        }
        S = S*quick_pow(T, n-k); writeln(S.a[fin][fin]);
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    第一篇阅读笔记
    课程信息管理系统
    HDU1124求n的阶乘后0的个数
    分解质因数算法
    牛客小白月赛23 B阶乘(质因数分解)
    JAVAWEB将图片铺满整个页面的方法
    Codeforces Global Round 7
    POJ--1703并查集(区分两个集合)
    POJ--1611经典并查集
    DFS,BFS回顾(各种题)(肺炎疫情中,祝平安)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8550127.html
Copyright © 2020-2023  润新知