[HNOI 2010]Bus 公交线路

Description

题库链接

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

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

\(1\leq N\leq 10^9,1<K\leq P\leq 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('\n'))
#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;
}

原文地址:https://www.cnblogs.com/NaVi-Awson/p/8550127.html

时间: 2024-08-02 21:34:25

[HNOI 2010]Bus 公交线路的相关文章

【BZOJ2004】[Hnoi2010]Bus 公交线路 状压+矩阵乘法

[BZOJ2004][Hnoi2010]Bus 公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站. 2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过). 3.公交车只能从编号较小的站台驶往编号较大的站台. 4.一辆公交车经过的

[BZOJ2004][Hnoi2010]Bus 公交线路

试题描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站. 2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过). 3.公交车只能从编号较小的站台驶往编号较大的站台. 4.一辆公交车经过的相邻两个站台间距离不得超过Pkm. 在最终设计线路之前,小Z想知道有多少

BZOJ 2004: [Hnoi2010]Bus 公交线路 [DP 状压 矩阵乘法]

传送门 题意: $n$个公交站点,$k$辆车,$1...k$是起始站,$n-k+1..n$是终点站 每个站只能被一辆车停靠一次 每辆车相邻两个停靠位置不能超过$p$ 求方案数 $n \le 10^9,\ p \le 8,\ k \le 10$ 思考过程中遇到的主要问题是“所有车是同时前进的”,既不能单独考虑一辆车又没法考虑前面的车队后面的影响 正确的做法是同时考虑所有车 每$p$个位置一定每辆车各停一次 $f[i][s]$表示当前在站点$i$,且$i$有车,$s$为车停靠状态 强制规定最靠左(即

[BZOJ 2004] [Hnoi2010] Bus 公交线路 【状压DP + 矩阵乘法】

题目链接: BZOJ - 2004 题目分析 看到题目完全不会..于是立即看神犇们的题解. 由于 p<=10 ,所以想到是使用状压.将每个连续的 p 个位置压缩成一个 p 位 2 进制数,其中共有 k 位是1,表示这 k 个位置是某辆 Bus 当前停下的位置.需要注意的是,每个状态的第一位必须是 1 ,这样保证了不会有重复的状态. 每个状态可以转移到右边的某些状态(由当前状态的第一个 1 移动).初始状态和终止状态都是前面 k 位是 1 .用矩阵转移 n - k 次. 代码 #include <

[HNOI2010]BUS 公交线路

题面 Bzoj Sol 状压很显然 重点在于转移:题目就相当与每\(p\)长度的车站必须有且仅有\(k\)个被经过 那么转移时状压的二进制一定要有\(k\)个一 且两个相邻转移的状态之间必须满足:设为\(i->j\),则\((i >> 1) \&j\)要有\(k-1\)个\(1\) 然后就可以加上矩阵快速幂优化,注意把满足要求的状态记下来,只有一百多个 我常数丑是我的错 # include <bits/stdc++.h> # define RG register #

爱帮公交查询之公交线路查询

今天,想在微信做一个公交查询的功能.到网上找了点资料,觉得爱帮挺好的于是注册了个帐号 api 页面 http://www.aibang.com/api/usage 公交线路查询 说明 公交线路查询,该接口根据关键字查询匹配的线路. 形式 http://openapi.aibang.com/bus/lines 例如:http://openapi.aibang.com/bus/lines?app_key=f41c8afccc586de03a99c86097e98ccb&city=%E5%8C%97%

公交线路免费api接口代码

描述:本接口主要是根据城市名称 +  线路名称 模糊查找城市公交线路信息. 开源api接口:http://openapi.aibang.com/bus/lines?app_key=f41c8afccc586de03a99c86097e98ccb&city="+cityName+"&q="+line 其中cityName = URLEncoder.encode(cityName,"utf-8") line = URLEncoder.encod

苏州公交线路api 查询公交详细信息

苏州公交线路api-苏州公交状态实时跟踪,查询公交详细信息. 接口名称:苏州公交线路api 接口平台:api接口 接口地址:http://apis.juhe.cn/szbusline/bus 支持格式:JSON/XML 请求方式:GET 请求示例:http://apis.juhe.cn/szbusline/bus?key=您申请的APPKEY&bus=11 苏州公交线路api调用代码JSON返回示例: { "resultcode":"200", "

全国公交线路导航

全国公交线路导航:可以查询到全国哪个城市的公交站点,线路,乘线路程等一系列信息! 详情参见;http://www.haoservice.com/docs/23 示例演示: { "error_code":0, "reason":"Success", "result":{ "busstops":[{ "adcode":320506, "citycode":"05