博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ2004][Hnoi2010]Bus 公交线路
阅读量:5332 次
发布时间:2019-06-15

本文共 2276 字,大约阅读时间需要 7 分钟。

[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想知道有多少种满足要求的方案。由于答案可能很大,你只需求出答案对30031取模的结果。

输入

仅一行包含三个正整数N K P,分别表示公交车站数,公交车数,相邻站台的距离限制。
N<=10^9,1<P<=10,K<N,1<K<=P

输出

仅包含一个整数,表示满足要求的方案数对30031取模的结果。

输入示例

10 2 4

输出示例

81

数据规模及约定

P<=10 , K <=8

题解

状压 dp + 矩阵乘法。

话说最近还想自己出一道这两种算法结合在一起的题呢。。。

这题目标状态只需要让 K 辆车分别在最后 K 个位置即可,顺序没有规定。所以这题设计状态时也不用考虑顺序。我们令 f(i, S) 表示前 i-1 个都已经经过了,第 i 到第 i + P - 1 个位置的状态为 S 的方案数,这里的“方案”可以理解成 K 个公交车所在位置的集合,也可以理解成覆盖过的位置的集合,这两个理解是等价的(原因在于我们转移时只考虑最靠左的公交车移到哪,与此同时 i 要加 1,即我们关注的位置区间向右错一格,所以一个公交车移开之后变成“没有公交车”状态的位置不会出现在状态中)。

由于 n 很大,而每次转移都是形如 f(i, S) -> f(i+1, tS),所以可以构造转移矩阵做矩阵快速幂。

注意最靠前那一位必须是 1,这样可以省掉一部分状态。

#include 
#include
#include
#include
#include
#include
using namespace std;int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f;}#define maxS 1024#define maxs 260#define MOD 30031struct Matrix { int n, m, A[maxs][maxs]; Matrix() { memset(A, 0, sizeof(A)); } Matrix(int _, int __): n(_), m(__) { memset(A, 0, sizeof(A)); } Matrix operator * (const Matrix& t) const { Matrix ans(n, t.m); for(int i = 1; i <= ans.n; i++) for(int j = 1; j <= ans.m; j++) for(int k = 1; k <= m; k++) ans.A[i][j] = (ans.A[i][j] + A[i][k] * t.A[k][j]) % MOD; return ans; } Matrix operator *= (const Matrix& t) { *this = *this * t; return *this; }} base, tr;Matrix Pow(Matrix a, int b) { Matrix ans = a, t = a; b--; while(b) { if(b & 1) ans *= t; t *= t; b >>= 1; } return ans;}int id[maxS], cnts;int main() { int n = read(), K = read(), P = read(); int all = (1 << P) - 1; for(int S = 0; S <= all; S++) { int cnt = 0; for(int j = 0; j < P; j++) cnt += S >> j & 1; if(cnt == K && (S & 1)) id[S] = ++cnts; } tr = Matrix(cnts, cnts); for(int S = 0; S <= all; S++) if(id[S]) { int tS = S >> 1; for(int j = 0; j < P; j++) if(!(tS >> j & 1) && id[tS|(1<

 

转载于:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6938919.html

你可能感兴趣的文章
Web服务器的原理
查看>>
小强升职计读书笔记
查看>>
常用的107条Javascript
查看>>
#10015 灯泡(无向图连通性+二分)
查看>>
忘记root密码,怎么办
查看>>
linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
查看>>
《黑客与画家》 读书笔记
查看>>
bzoj4407: 于神之怒加强版
查看>>
mysql统计一张表中条目个数的方法
查看>>
ArcGIS多面体(multipatch)解析——引
查看>>
css3渐变画斜线 demo
查看>>
JS性能DOM优化
查看>>
设计模式 单例模式 使用模板及智能指针
查看>>
c#的const可以用于引用类型吗
查看>>
手动实现二值化
查看>>
What Linux bind mounts are really doing
查看>>
linux top命令详解
查看>>
博弈论小结
查看>>
模拟Post登陆带验证码的网站
查看>>
NYOJ458 - 小光棍数
查看>>