代码改变世界
[登录 · 注册]
  • [BZOJ2004][Hnoi2010]Bus 公交线路
  • [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想知道有多少种满足要求的方案。由于答案可能很大,你只需求出答案对30031取模的结果。

    输入

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

    输出

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

    输入示例

    10 2 4

    输出示例

    81

    数据规模及约定

    P<=10 , K <=8

    题解

    状压 dp + 矩阵乘法。

    话说最近还想自己出一道这两种算法结合在一起的题呢。。。

    这题目标状态只需要让 K 辆车分别在最后 K 个位置即可,顺序没有规定。所以这题设计状态时也不用考虑顺序。我们令 f(i, S) 表示前 i-1 个都已经经过了,第 i 到第 i + P - 1 个位置的状态为 S 的方案数,这里的“方案”可以理解成 K 个公交车所在位置的集合,也可以理解成覆盖过的位置的集合,这两个理解是等价的(原因在于我们转移时只考虑最靠左的公交车移到哪,与此同时 i 要加 1,即我们关注的位置区间向右错一格,所以一个公交车移开之后变成“没有公交车”状态的位置不会出现在状态中)。

    由于 n 很大,而每次转移都是形如 f(i, S) -> f(i+1, tS),所以可以构造转移矩阵做矩阵快速幂。

    注意最靠前那一位必须是 1,这样可以省掉一部分状态。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxS 1024
    #define maxs 260
    #define MOD 30031
    
    struct Matrix {
    	int n, m, A[maxs][maxs];
    	
    	Matrix() { memset(A, 0, sizeof(A)); }
    	Matrix(int _, int __): n(_), m(__) { memset(A, 0, sizeof(A)); }
    	
    	Matrix operator * (const Matrix& t) const {
    		Matrix ans(n, t.m);
    		for(int i = 1; i <= ans.n; i++)
    			for(int j = 1; j <= ans.m; j++)
    				for(int k = 1; k <= m; k++)
    					ans.A[i][j] = (ans.A[i][j] + A[i][k] * t.A[k][j]) % MOD;
    		return ans;
    	}
    	Matrix operator *= (const Matrix& t) {
    		*this = *this * t;
    		return *this;
    	}
    } base, tr;
    
    Matrix Pow(Matrix a, int b) {
    	Matrix ans = a, t = a; b--;
    	while(b) {
    		if(b & 1) ans *= t;
    		t *= t; b >>= 1;
    	}
    	return ans;
    }
    
    int id[maxS], cnts;
    
    int main() {
    	int n = read(), K = read(), P = read();
    	
    	int all = (1 << P) - 1;
    	for(int S = 0; S <= all; S++) {
    		int cnt = 0;
    		for(int j = 0; j < P; j++) cnt += S >> j & 1;
    		if(cnt == K && (S & 1)) id[S] = ++cnts;
    	}
    	tr = Matrix(cnts, cnts);
    	for(int S = 0; S <= all; S++) if(id[S]) {
    		int tS = S >> 1;
    		for(int j = 0; j < P; j++) if(!(tS >> j & 1) && id[tS|(1<<j)]) tr.A[id[tS|(1<<j)]][id[S]]++;
    	}
    	base = Matrix(cnts, 1);
    	base.A[1][1] = 1;
    	
    	base = Pow(tr, n - K) * base;
    	printf("%d
    ", base.A[1][1]);
    	
    	return 0;
    }
    
  • 【推广】 阿里云小站-上云优惠聚集地(新老客户同享)更有每天限时秒杀!
    【推广】 云服务器低至0.95折 1核2G ECS云服务器8.1元/月
    【推广】 阿里云老用户升级四重礼遇享6.5折限时折扣!
  • 原文:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6938919.html
Copyright 2008-2020 晋ICP备12007731号-1