[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[ ...
随机推荐
- DevExpress 2019 .NET产品现已完全支持Visual Studio 2019
[DevExpress v18.2.8最新版免费下载] 我们非常高兴地跟宣布DevExpress .NET产品现已完全支持Visual Studio 2019.如果您是DevExpress忠实用户,可 ...
- 【NOIP2013模拟联考5】军训
题目 HYSBZ 开学了!今年HYSBZ 有n 个男生来上学,学号为1-n,每个学生都必须参加军训.在这种比较堕落的学校里,每个男生都会有Gi 个女朋友,而且每个人都会有一个欠扁值Hi.学校为了保证军 ...
- 从1G到5G,移动通信发展之路
2G取代1G是历史的必然,诺基亚是2G时代的领航者. 3G是个“半吊子”系统,2G手机只能打电话.发短信,上网很困难.3G的通信标准将信息的传输率提高了一个数量级,这是一个飞跃,它使得移动互联网得以实 ...
- linux运维、架构之路-Kubernetes本地镜像仓库+dashboard部署
一.部署docker registry 生产环境中我们一般通过搭建本地的私有镜像仓库(docker registry)来拉取镜像. 1.拉取registry镜像 [root@k8 ...
- Python3 三元表达式、列表推导式、生成器表达式
Python3 三元表达式.列表推导式.生成器表达式 三元表达式 表达式中,有三个元素 name = input("请输入姓名: ")ret = '输入正确' if name == ...
- tomcat 启动一傘而过问题
tomcat 启动一傘而过问题 D:\apache-tomcat-7.0.75\bin startup.bat打开记事本打开 第一行:设置启动环境变量JAVA_HOME,CATALINA_HOME S ...
- 如何使 C++ 的 StringBuilder 提升 4350% 的性能?
介绍 经常出现客户端打电话抱怨说:你们的程序慢如蜗牛.你开始检查可能的疑点:文件IO,数据库访问速度,甚至查看web服务. 但是这些可能的疑点都很正常,一点问题都没有. 你使用最顺手的性能分析工具分析 ...
- mysql FOREIGN KEY约束 语法
mysql FOREIGN KEY约束 语法 作用:一个表中的 FOREIGN KEY 指向另一个表中的 PRIMARY KEY. DD马达 说明:FOREIGN KEY 约束用于预防破坏表之间连接的 ...
- SVN 没有弹出输入账号和密的界面
在用TortoiseSVN的时候,点SVN Checkout输入URL之后没有提示要输入账号密码的弹出框,直接跳到下一个界面,解决办法: 因为你在初次登陆svn的时候,点了保存密码的复选框,所以只要清 ...
- luogu 2219[HAOI2007]修筑绿化带 单调队列
Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in",& ...