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

题目链接: BZOJ - 2004

题目分析

看到题目完全不会。。于是立即看神犇们的题解。

由于 p<=10 ,所以想到是使用状压。将每个连续的 p 个位置压缩成一个 p 位 2 进制数,其中共有 k 位是1,表示这 k 个位置是某辆 Bus 当前停下的位置。需要注意的是,每个状态的第一位必须是 1 ,这样保证了不会有重复的状态。 每个状态可以转移到右边的某些状态(由当前状态的第一个 1 移动)。初始状态和终止状态都是前面 k 位是 1 。用矩阵转移 n - k 次。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

const int MaxMap = 130 + 5, Mod = 30031;

int N, K, P, Top, Rec;
int L[MaxMap];

int Calc(int Num) {
	int Cnt = 0;
	while (Num) {
		++Cnt;
		Num -= Num & -Num;
	}
	return Cnt;
}

bool Check(int x, int y) {
	x = (x - (1 << (P - 1))) << 1;
	int t = x ^ y;
	if (t - (t & -t) == 0) return true;
	return false;
}

struct Matrix
{
	int x, y, Num[MaxMap][MaxMap];
	void SetXY(int a, int b) {
		x = a; y = b;
	}
	void Clear(int xx) {
		for (int i = 1; i <= x; ++i) {
			for (int j = 1; j <= y; ++j) {
				Num[i][j] = xx;
			}
		}
	}
} M0, MZ;

Matrix Mul(Matrix A, Matrix B) {
	Matrix ret;
	ret.SetXY(A.x, B.y);
	ret.Clear(0);
	for (int i = 1; i <= ret.x; ++i) {
		for (int j = 1; j <= ret.y; ++j) {
			for (int k = 1; k <= A.y; ++k) {
				ret.Num[i][j] += A.Num[i][k] * B.Num[k][j];
				ret.Num[i][j] %= Mod;
			}
		}
	}
	return ret;
}

Matrix Pow(Matrix A, int b) {
	Matrix ret, f;
	f = A;
	ret.SetXY(f.x, f.y);
	ret.Clear(0);
	for (int i = 1; i <= ret.x; ++i) ret.Num[i][i] = 1;
	while (b) {
		if (b & 1) ret = Mul(ret, f);
		b >>= 1;
		f = Mul(f, f);
	}
	return ret;
}

int main()
{
	scanf("%d%d%d", &N, &K, &P);
	Top = 0;
	for (int i = (1 << (P - 1)); i <= (1 << P) - 1; ++i) {
		if (Calc(i) == K) {
			L[++Top] = i;
			if (i == (1 << P) - 1 - ((1 << (P - K)) - 1)) Rec = Top;
		}
	}
	MZ.SetXY(Top, Top);
	MZ.Clear(0);
	M0.SetXY(1, Top);
	M0.Clear(0);
	M0.Num[1][Rec] = 1;
	for (int i = 1; i <= Top; ++i) {
		for (int j = 1; j <= Top; ++j) {
			if (Check(L[i], L[j])) MZ.Num[i][j] = 1;
		}
	}
	MZ = Pow(MZ, N - K);
	M0 = Mul(M0, MZ);
	printf("%d\n", M0.Num[1][Rec]);
	return 0;
}

  

时间: 2024-10-08 16:21:23

[BZOJ 2004] [Hnoi2010] Bus 公交线路 【状压DP + 矩阵乘法】的相关文章

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

公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站. 2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过). 3.公交车只能从编号较小的站台驶往编号较大的站台. 4.一辆公交车经过的相邻两个 站台间距离不得超过Pkm. 在最终设计

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

[BZOJ2004][Hnoi2010]Bus 公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站. 2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过). 3.公交车只能从编号较小的站台驶往编号较大的站台. 4.一辆公交车经过的

BZOJ 2004: [Hnoi2010]Bus 公交线路 [DP 状压 矩阵乘法]

传送门 题意: $n$个公交站点,$k$辆车,$1...k$是起始站,$n-k+1..n$是终点站 每个站只能被一辆车停靠一次 每辆车相邻两个停靠位置不能超过$p$ 求方案数 $n \le 10^9,\ p \le 8,\ k \le 10$ 思考过程中遇到的主要问题是“所有车是同时前进的”,既不能单独考虑一辆车又没法考虑前面的车队后面的影响 正确的做法是同时考虑所有车 每$p$个位置一定每辆车各停一次 $f[i][s]$表示当前在站点$i$,且$i$有车,$s$为车停靠状态 强制规定最靠左(即

【弱校胡策】2016.4.14 (bzoj2164)最短路+状压DP+矩阵乘法+高斯消元+树链剖分+线段树+背包DP

cyyz&qhyz&lwyz&gryz弱校胡策 命题人:cyyz ws_fqk T3暴力写挫了 50+10+0滚粗辣! 奇妙的约会(appointment.cpp/c/pas) [问题描述] DQS和sxb在网上结识后成为了非常好的朋友,并且都有着惊人 的OI水平.在NOI2333的比赛中,两人均拿到了金牌,并保送进入 HU/PKU.于是两人决定在这喜大普奔的时刻进行面基. NOI2333参赛选手众多,所以安排了n个考点,DQS在1号考点, 而sxb在n号考点.由于是举办全国性赛事

[BZOJ2004][Hnoi2010]Bus 公交线路

试题描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站. 2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过). 3.公交车只能从编号较小的站台驶往编号较大的站台. 4.一辆公交车经过的相邻两个站台间距离不得超过Pkm. 在最终设计线路之前,小Z想知道有多少

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

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant Accepts: 38 Submissions: 108 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 小明很喜欢国际象棋,尤其喜欢国际象棋里面的大象(只要无阻挡能够斜着走任意格),但是他觉得国际象棋里的大象太凶残了,于是他

[BZOJ 1072] [SCOI2007] 排列perm 【状压DP】

题目链接:BZOJ 1072 这道题使用 C++ STL 的 next_permutation() 函数直接暴力就可以AC .(使用 Set 判断是否重复) 代码如下: #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <set>

BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp... dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s . 考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king ) 我有各种预处理所以 code 的方程和这有点不一样 ------------------------------------------------

BZOJ 3446: [Usaco2014 Feb]Cow Decathlon( 状压dp )

水状压dp. dp(x, s) = max{ dp( x - 1, s - {h} ) } + 奖励(假如拿到的) (h∈s). 时间复杂度O(n * 2^n) ---------------------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x