码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-12-13 09:33:04      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:blog   http   io   ar   os   使用   sp   for   on   

题目链接: 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;	
}

  

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

标签:blog   http   io   ar   os   使用   sp   for   on   

原文地址:http://www.cnblogs.com/JoeFan/p/4160902.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!