[Bzoj2004][Hnoi2010]Bus 公交线路(状压dp&&矩阵加速)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2004
看了很多大佬的博客才理解了这道题,菜到安详QAQ
在不考虑优化的情况下,先推$dp$式子,设$dp[i][j]$为最慢的公交车走到了第$i$站,$[i,i+p-1]$站的状态为$j$时的方案数。$i$到$i+p-1$的范围内有且仅有$k$辆车,则状态$j$应该为$p$长度的二进制串,其中有且仅有$k$个$1$(表示$k$辆车)并且第$1$位一定为$1$(第$1$位对应了当前的位置)。则初始态为$dp[0][111(k个1)…000(p-k个0)]$,结束态为$dp[n-k][111(k个1)…000(p-k个0)]$。判断状态$w$是否可以转移到状态$e$,则判断$w$的第$2$位到第$p+1$位($p+1$位补零)是否与$e$的第$1$位到$p$位只有一位不同,是则可以转移$dp[i][e]+=dp[i-1][w]$;
这时候考虑优化,$n<=1e9$就注定要矩阵快速幂加速,则先处理出所有状态之间的关系并构建矩阵$d[i][j]$,$d[i][j]$为$1$表示第一次第$i$个状态可以转移到第$j$个状态。我们要求的是第$n-k$次后初始态到结束态的方案数,根据矩阵乘法的定义$d[i][j]=\sum_{k=1}^{n}d[i][k]*d[k][j]$,则我们只要将矩阵连乘$(n-k)$次,d[结束态][初始态]就是我们所求的。而初始态和结束态实际上是一样的。
当n较小时可以状压dp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = ;
int check(int x) {//判断x状态中1的个数
int sum = ;
while (x) {
sum++;
x -= (x&(-x));
}
return sum;
}
int dp[][ << ];
int main() {
int n, k, p;
while (scanf("%d%d%d", &n, &k, &p) != EOF) {
memset(dp, , sizeof(dp));
int End;
for (int i = ( << (p - )); i < ( << p); i++) {
if (i == ( << p) - - (( << (p - k)) - ))
End = i;
}
dp[][End] = ;
for (int i = ; i <= n - k; i++) {
for (int j = ( << (p - )); j < ( << p); j++) {
for (int w = ( << (p - )); w < ( << p); w++) {
if (check(j) == check(w) && check(j) == k) {
int q = (w - ( << (p - ))) << ;
int t = (q^j);
if (t == (t&(-t))) {
dp[i][j] = (dp[i][j] + dp[i - ][w]) % mod;
}
}
}
}
}
printf("%d\n", dp[n - k][End]);
}
}
本题正解:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = ;
int check(int x) {//判断x中1的个数
int sum = ;
while (x) {
sum++;
x -= (x&(-x));
}
return sum;
}
struct martix {
int tmp[][];
int num;
martix operator *(const martix &b)const {
martix ans;
ans.num = num;
for (int i = ; i <= num; i++) {
for (int j = ; j <= num; j++) {
ans.tmp[i][j] = ;
for (int k = ; k <= num; k++) {
ans.tmp[i][j] += tmp[i][k] * b.tmp[k][j];
ans.tmp[i][j] %= mod;
}
}
}
return ans;
}
};
martix qpow(martix a, int x) {
martix ans;
ans.num = a.num;
memset(ans.tmp, , sizeof(ans.tmp));
for (int i = ; i <= ans.num; i++)
ans.tmp[i][i] = ;
while (x) {
if (x & )
ans = ans * a;
a = a * a;
x /= ;
}
return ans;
}
int statu[ << ];
int main() {
int n, k, p;
while (cin >> n >> k >> p) {
martix a;
int len = , End;
for (int i = ( << (p - )); i < ( << p); i++) {
if (check(i) == k) {
statu[++len] = i;
if (i == ( << p) - - (( << (p - k)) - ))
End = len;
}
}
a.num = len;
memset(a.tmp, , sizeof(a.tmp));
for (int i = ; i <= len; i++) {
for (int j = ; j <= len; j++) {
int q = (statu[j] - ( << (p - ))) << ;
int t = (q^statu[i]);
if (t == (t&(-t)))
a.tmp[i][j] = ;
}
}
a = qpow(a, n - k);
printf("%d\n", a.tmp[End][End]);
}
}
[Bzoj2004][Hnoi2010]Bus 公交线路(状压dp&&矩阵加速)的更多相关文章
- BZOJ2004:[HNOI2010]Bus 公交线路(状压DP,矩阵乘法)
Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定 ...
- 【bzoj2004】[Hnoi2010]Bus 公交线路 状压dp+矩阵乘法
题目描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计 ...
- 【BZOJ】2004: [Hnoi2010]Bus 公交线路 状压DP+矩阵快速幂
[题意]n个点等距排列在长度为n-1的直线上,初始点1~k都有一辆公车,每辆公车都需要一些停靠点,每个点至多只能被一辆公车停靠,且每辆公车相邻两个停靠点的距离至多为p,所有公车最后会停在n-k+1~n ...
- 【BZOJ2004】[Hnoi2010]Bus 公交线路 状压+矩阵乘法
[BZOJ2004][Hnoi2010]Bus 公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1 ...
- 『公交线路 状压dp 矩阵乘法加速』
公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的 ...
- BZOJ 2004 公交线路(状压DP+矩阵快速幂)
注意到每个路线相邻车站的距离不超过K,也就是说我们可以对连续K个车站的状态进行状压. 然后状压DP一下,用矩阵快速幂加速运算即可. #include <stdio.h> #include ...
- BZOJ2004: [Hnoi2010]Bus 公交线路
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2004 状压dp+矩阵乘法. f[i][s]表示从第i位至前面的i-k位,第i位必须取的状态. ...
- bzoj2004 [Hnoi2010]Bus 公交线路 矩阵快速幂+状压DP
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2004 题解 如果 \(N\) 没有那么大,考虑把每一位分配给每一辆车. 假设已经分配到了第 \ ...
- HDU 5564 Clarke and digits 状压dp+矩阵加速
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5564 题意: 求长度在[L,R]范围,并且能整除7的整数的总数. 题解: 考虑最原始的想法: dp[ ...
随机推荐
- Attention Points
Attention Points 数组范围 无向图.树,边表的范围是边数的两倍. 因为最近树的题目做的比较多,一定要注意分清是树还是图,不能冲上去就去开struct Edge{int to,ne,w; ...
- Python---进阶---多线程---threading
一. 使用多线程去播放两个播放列表,一个是movie,一个是music _thread threading ------------------------------------------ imp ...
- [原创]Laravel 基于redis队列的解析
目录 参考链接 本文环境 为什么使用队列 Laravel 中的队列 分发任务 任务队列 Worker Last-Modified: 2019年5月10日11:44:18 参考链接 使用 Laravel ...
- ie下,首页打开页面非常慢
手里的项目,登录页面在IE下首次进入页面非常的慢,应该不只是登录页面,因为项目我也是半路接手的.开始以为是js的问题,后台把所有的代码都去掉,就一个空白的页面,然后慢慢的试试,最后才发现是一个CSS文 ...
- js 遍历数组取出字符串用逗号拼接
var arr = [{"name":"hhh"},{"name":"dddd"}] //用js function ge ...
- Oracle的分页和MySQL的分页
Oracle的分页: select * from ( select rownum r,a from tabName where rownum <= 20 ) where r > 10 使用 ...
- js返回上一页并刷新 代码整理
真正好用: 强制载入后刷新一次 在要载入的页面加入以下代码: <script> if(window.name != "bencalie"){ location.relo ...
- Android-Studio:Cannot reload AVD list
Android-Studio:Cannot reload AVD list 今天用Android-Studio时点击"RUN"后出现如下错误,特此记录一下解决方案. Cannot ...
- Spark Streaming的优化之路—从Receiver到Direct模式
作者:个推数据研发工程师 学长 1 业务背景 随着大数据的快速发展,业务场景越来越复杂,离线式的批处理框架MapReduce已经不能满足业务,大量的场景需要实时的数据处理结果来进行分析.决 ...
- Mybatis, 实现一对多
我这里是拿商品做为例子 不多说直接上代码 Mapper.xml <?xml version="1.0" encoding="UTF-8"?> < ...