<更新提示>

<第一次更新>


<正文>

公交线路

Description

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

1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站。

2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过)。

3.公交车只能从编号较小的站台驶往编号较大的站台。

4.一辆公交车经过的相邻两个

站台间距离不得超过Pkm。 在最终设计线路之前,小Z想知道有多少种满足要求的方案。由于答案可能很大,你只

需求出答案对30031取模的结果。

Input Format

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

N<=10^9,1<P<=10,K<N,1<K<=P

Output Format

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

Sample Input

10 2 4

Sample Output

81

解析

问题转换:求个\(n\)个变量\(x_{1-n}\)赋\([1,k]\)之间的值的方案数,需要满足:\(x_{1-k}\)取遍\(1-k\),\(x_{(n-k+1)-n}\)取遍\(1-k\),任意一个区间\([t,t+p-1]\)中\(1-k\)的数至少出现一次。

距离的限制其实就是上述问题转换中的最后一条限制。

考虑状压\(dp\),由于\(p\)很小,我们就压一下当前阶段那个长度为\(p\)的区间的赋值情况。也就是说,\(f[i][S]\)代表前\(i-1\)个变量一个完成赋值,区间\([i,i+p-1]\)中\(1-k\)这些数的赋值情况为\(S\)的方案数。\(S\)是一个长度为\(p\)的二进制数,共有\(k\)个\(1\),从最高位开始数,\(S\)的第\(j\)位为\(1\),代表\(x_{i+j-1}\)被赋值为了一个\(1-k\)之间的数(我们不关心每一个数的具体位置,只需要保证这\(k\)个数在这个区间内每个出现至少一次即可),作为当前区间合法性的关键值,其他变量随意。对于任意的\(S\),需满足最高位为\(1\),是因为我们必须保证第\(i\)位取,这样才能保证最后所有变量都赋了值。

转移当然是由上一个阶段转移而来,方程就是:

\[f[i][S]=\sum_{valid(S',S)} f[i-1][S']
\]

如何判定两个状态直接可以转移?首先两个状态的区间只差了一个位置。也就是\(S'\)的最高位在\(S\)中不存在,那么我们就把最高位取走,然后在最低位后面补\(0\),如果此时\(S'\)是\(S\)的子集,那么我们只需在第\(i+p-1\)这个位置补上刚才取走的那个数就又是合法的方案了。所以,当操作完后的状态\(S'\)是\(S\)的子集时,可以转移。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+20 , SIZE = 130 , Mod = 30031;
int n,K,P,f[N][SIZE],S[SIZE],tot,ans;
inline void input(void)
{
scanf("%d%d%d",&n,&K,&P);
}
inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
inline void Add(int &a,int b) { a = add( a , b ); }
inline void DynamicProgram(void)
{
for (int i=1<<P-1;i<1<<P;i++)
{
int cnt = 0;
for (int j=1;j<=P;j++)
cnt += ( i >> (j-1) & 1 );
if ( cnt == K ) S[++tot] = i;
}
f[1][tot] = 1;
for (int i=2;i<=n-K+1;i++)
for (int j=1;j<=tot;j++)
for (int k=1;k<=tot;k++)
{
int S1 = S[k] , S2 = S[j];
int S3 = S1 - (1<<P-1) << 1;
for (int l=1;l<=P;l++)
if ( not( S3 >> (l-1) & 1 ) && ( S3 + (1<<l-1) == S2 ) )
Add( f[i][j] , f[i-1][k] );
}
}
int main(void)
{
input();
DynamicProgram();
printf("%d\n",f[n-K+1][tot]);
return 0;
}

这样的动态规划算法的时间复杂度为\(O(nC_{p-1}^{k-1})\),使用矩阵乘法加速,时间复杂度为\(O((C_{p-1}^{k-1})^3\log_2n)\)。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+20 , SIZE = 130 , Mod = 30031;
int n,K,P,S[SIZE],f[SIZE],tot;
inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
inline int mul(int a,int b) { return 1LL * a * b % Mod; }
inline void Add(int &a,int b) { a = add( a , b ); }
struct Matrix
{
int mat[SIZE][SIZE];
Matrix () { memset( mat , 0 , sizeof mat ); }
friend Matrix operator * (Matrix a,Matrix b)
{
Matrix c;
for (int i=1;i<=tot;i++)
for (int j=1;j<=tot;j++)
for (int k=1;k<=tot;k++)
Add( c.mat[i][j] , mul( a.mat[i][k] , b.mat[k][j] ) );
return c;
}
};
Matrix Trans;
inline void Maxtrixmul(int *a,Matrix b)
{
int c[SIZE] = {};
for (int j=1;j<=tot;j++)
for (int k=1;k<=tot;k++)
Add( c[j] , mul( a[k] , b.mat[k][j] ) );
memcpy( a , c , sizeof c );
}
inline void DynamicProgram(void)
{
for (int i=1<<P-1;i<1<<P;i++)
{
int cnt = 0;
for (int j=1;j<=P;j++)
cnt += ( i >> (j-1) & 1 );
if ( cnt == K ) S[++tot] = i;
}
for (int i=1;i<=tot;i++)
for (int j=1;j<=tot;j++)
{
int S1 = S[i] , S2 = S[j];
int S3 = S1 - (1<<P-1) << 1;
for (int k=1;k<=P;k++)
if ( not( S3 >> (k-1) & 1 ) && ( S3 + (1<<k-1) == S2 ) )
Trans.mat[i][j] = 1;
}
int T = n - K; f[tot] = 1;
while ( T )
{
if ( 1 & T ) Maxtrixmul( f , Trans );
Trans = Trans * Trans , T >>= 1;
}
}
int main(void)
{
scanf("%d%d%d",&n,&K,&P);
DynamicProgram();
printf("%d\n",f[tot]);
return 0;
}

<后记>

『公交线路 状压dp 矩阵乘法加速』的更多相关文章

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

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

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

    Description 小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 公交线路(状压dp&&矩阵加速)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2004 看了很多大佬的博客才理解了这道题,菜到安详QAQ 在不考虑优化的情况下,先推$dp ...

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

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

  6. nyoj1273 河南省第九届省赛_"宣传墙"、状压DP+矩阵幂加速

    宣传墙 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 ALPHA 小镇风景美丽,道路整齐,干净,到此旅游的游客特别多.CBA 镇长准备在一条道路南 面 4*N 的墙上做 ...

  7. [BZOJ 2004] [Hnoi2010] Bus 公交线路 【状压DP + 矩阵乘法】

    题目链接: BZOJ - 2004 题目分析 看到题目完全不会..于是立即看神犇们的题解. 由于 p<=10 ,所以想到是使用状压.将每个连续的 p 个位置压缩成一个 p 位 2 进制数,其中共 ...

  8. HDU 5434 Peace small elephant 状压dp+矩阵快速幂

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant  Accepts: 38  Submissions: ...

  9. BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

    状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...

随机推荐

  1. [算法]LeetCode 152:乘积最大子序列

    题目描述: 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4]输出: 6解释: 子数组 [2,3] 有最大乘积 6.示 ...

  2. wpf 当DataGrid列模版是ComboBox时,显示信息

    ​ 实际工作中,有时DataGrid控件某一列显示数据是从Enum集合里面选择出来的,那这时候设置列模版为ComboBox就能满足需求.而关于显示的实际内容,直接是Enum的string()返回值可能 ...

  3. 湖南省web应用软件(中慧杯)

    湖南省web应用软件 写这篇博客已经是比完赛的第四天了,我还记得那天下着小雨.我们早早的到了比赛的现场抽检机器,在比赛前一天我很是激动.我还记得我们从学校,去株洲的时候我们的领导来给我加油,特别是我的 ...

  4. Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之三 || Swagger的使用 3.1

    本文梯子 本文3.0版本文章 常见问题 1.Bug调试 2.经常有小伙伴遇到这个错误 3.路由重载 一.为什么使用Swagger 二.配置Swagger服务 1.引用Nuget包 2.配置服务 3.启 ...

  5. 从《华为的冬天》到AI的冬天 | 甲子光年

    知难不难,惶者生存. 作者 | DougLong 编辑 | 火柴Q.甲小姐 *本文为甲子光年专栏作家DougLong独家稿件.作者为AI从业者.Gary Marcus<Rebooting AI& ...

  6. php 的定界符 <<<eof

    PHP是一个Web编程语言,在编程过程中难免会遇到用echo来输出大段的html和javascript脚本的情况,如果用传统的输出方法 ——按字符串输出的话,肯定要有大量的转义符来对字符串中的引号等特 ...

  7. iOS UItableview 镶嵌 collectionView ,cell 自适应高度动态布局

    最近在写这个功能,之前看到很多,可是需求一直没有涉及到,大致思路是有的,发现,网上的大部分都有缺陷和bug,我也是好无语啦啦啦,也不晓得是不是升级 了xcode,一样的代码,允许的效果都不一样,,,苦 ...

  8. tmux:终端复用神器

    一.简介与安装 今天无意间从同事那里知道有 tmux 这种神器,tmux(terminal multiplexer)是Linux上的终端复用神器,可从一个屏幕上管理多个终端(准确说是伪终端).使用该工 ...

  9. MQL语句

    最近工作经常需要用到MQL语句,记录下备忘. temp query bus * s003 * select id; 第一个*代表type,第二个s003代表名称,第三个*代表版本. 先通过id查询s0 ...

  10. 9. Go语言—流程控制

    一.流程控制语法 if condition_1{ }else if condition_2{ }else if condition_3{ }else{ } 二.switch分支 package mai ...