题目链接: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&&矩阵加速)的更多相关文章

  1. BZOJ2004:[HNOI2010]Bus 公交线路(状压DP,矩阵乘法)

    Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定 ...

  2. 【bzoj2004】[Hnoi2010]Bus 公交线路 状压dp+矩阵乘法

    题目描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计 ...

  3. 【BZOJ】2004: [Hnoi2010]Bus 公交线路 状压DP+矩阵快速幂

    [题意]n个点等距排列在长度为n-1的直线上,初始点1~k都有一辆公车,每辆公车都需要一些停靠点,每个点至多只能被一辆公车停靠,且每辆公车相邻两个停靠点的距离至多为p,所有公车最后会停在n-k+1~n ...

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

    [BZOJ2004][Hnoi2010]Bus 公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1 ...

  5. 『公交线路 状压dp 矩阵乘法加速』

    公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的 ...

  6. BZOJ 2004 公交线路(状压DP+矩阵快速幂)

    注意到每个路线相邻车站的距离不超过K,也就是说我们可以对连续K个车站的状态进行状压. 然后状压DP一下,用矩阵快速幂加速运算即可. #include <stdio.h> #include ...

  7. BZOJ2004: [Hnoi2010]Bus 公交线路

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2004 状压dp+矩阵乘法. f[i][s]表示从第i位至前面的i-k位,第i位必须取的状态. ...

  8. bzoj2004 [Hnoi2010]Bus 公交线路 矩阵快速幂+状压DP

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2004 题解 如果 \(N\) 没有那么大,考虑把每一位分配给每一辆车. 假设已经分配到了第 \ ...

  9. HDU 5564 Clarke and digits 状压dp+矩阵加速

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5564 题意: 求长度在[L,R]范围,并且能整除7的整数的总数. 题解: 考虑最原始的想法: dp[ ...

随机推荐

  1. 设置mysql数据表列自动递增以及数据行插入操作

    创建mysql数据表,设置id列递增.主键create table running_log ( id int primary key auto_increment, routename varchar ...

  2. flask项目中设置logo

    <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}&qu ...

  3. classloader加载class的流程及自定义ClassLoader

    java应用环境中不同的class分别由不同的ClassLoader负责加载.一个jvm中默认的classloader有Bootstrap ClassLoader.Extension ClassLoa ...

  4. 【01】Python 环境变量、条件判断、循环、基本运算符

    1 环境变量 1.1 Windows下环境变量 系统变量Path中要加入Python安装路径: C:\xxxx\Python36;C:\xxxx\Python36\Scripts; 2 条件判断 2. ...

  5. 用vue构建项目同一局域网下通过ip访问

    在webpack配置文件下改为 host:'0.0.0.0' 改为后启动跳转不到登录页面 需手动修改浏览器上的0.0.0.0:8080为自己ip加上:8080 就可以在别的电脑上进行访问了 举一反三: ...

  6. 可用来修改bean对象的BeanPostProcessor

    可用来修改bean对象的BeanPostProcessor 11.1 简介 BeanPostProcessor是Spring中定义的一个接口,其与之前介绍的InitializingBean和Dispo ...

  7. (3.2)狄泰软件学院C++课程学习剖析三

    对课程前面40课的详细回顾分析(一) 0. int main() { // ① Array t(3,3); //普通模式 // ② Array *t=new Array(3,3); //指针方式 // ...

  8. Java数据结构之单链表

    这篇文章主要讲解了通过java实现单链表的操作,一般我们开始学习链表的时候,都是使用C语言,C语言中我们可以通过结构体来定义节点,但是在Java中,我们没有结构体,我们使用的是通过类来定义我们所需要的 ...

  9. Gradle 学习笔记

    配置 Gradle 的环境变量 export GRADLE_HOME=/opt/software/java/gradle-3.1 export PATH=\(PATH:\)GRADLE_HOME/bi ...

  10. php简单随机实现发红包程序

    前言: 使用PHP发红包,当我们输入红包数量和总金额后,PHP会根据这两个值进行随机分配每个金额,保证每个人都能领取到一个红包,每个红包金额不等,就是要求红包金额要有差异,所有红包金额总额应该等于总金 ...