题目链接: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. Spring Cloud(1)相关概念

    单点系统架构 传统项目架构 传统项目分为三层架构,将业务逻辑层.数据库访问层.控制层放入在一个项目中. 优点:适合于个人或者小团队开发,不适合大团队开发. 分布式项目架构 根据业务需求进行拆分成N个子 ...

  2. 【华容道】题解(NOIP2013提高组day2)

    分析 这道题很容易想到令f[x][y][x1][y1]表示空白块在(x,y).指定棋子在(x1,y1)时的最少步数,让空白块和四周的棋子交换,当空白块要和指定棋子交换时,把指定棋子移动,搞一下BFS就 ...

  3. ubuntu1804隐藏顶部工作栏

    先安装 sudo apt-get install gnome-shell-extension-autohidetopbar 然后安装 sudo apt-get install gnome-shell- ...

  4. .Net手动实现ORM及代码生自动成器

    序言 代码生成器 同时提供便捷的开发管理功能和多项开发工作中常用到的辅助工具功能,您可以很方便轻松地进行项目开发,让软件开发变得轻松而快乐!帮您快速开发项目,缩短开发周期,减少开发成本,大大提高了企业 ...

  5. Python_018( isinstance,issubclass详解)

    1.isinstance() 1)class A:pass class B:pass b = B() print(isinstance(b,B) #True  #isinstance(obj,type ...

  6. 【PowerOJ1742&网络流24题】试题库问题(最大流)

    题意: 思路: [问题分析] 二分图多重匹配问题,用最大流解决. [建模方法] 建立二分图,每个类别为X集合中的顶点,每个题为Y集合中的顶点,增设附加源S和汇T. 1.从S向每个Xi连接一条容量为该类 ...

  7. 前端HTTP缓存

    Web 缓存大致可以分为:数据库缓存.服务器端缓存(代理服务器缓存.CDN 缓存).浏览器缓存.其中前端比较关心的是浏览器缓存,包括今天要说的HTTP缓存和前面说过的cookie.localStora ...

  8. Django REST framework入门 (转自中文文档)

    快速入门 我们将创建一个简单的允许管理员用户查看和编辑系统中的用户和组的API. 项目设置 创建一个名为 tutorial 的新django项目,然后启动一个名为 quickstart 的新app. ...

  9. Android实现无标题栏全屏的三种方法

    一.通过Java代码 在setContentView之前执行: requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏 getWindow().se ...

  10. 动态GI

    在Engine/Config 目录中找到ConsoleVariables.ini并打开,在其中加入 r.LightPropagationVolume = 1 ,保存,重启引擎 如果场景中有Post P ...