bzoj 2004: [Hnoi2010]Bus 公交线路

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

解题报告:
用时:2h30min,1AC
这题拿着毫无办法,只能请教大佬,原来是矩阵优化DP,这个DP也是非常的诡异,首先我们要保证移动不超过P,所以我们以P为单位做矩阵,然后P很小可以状压,所以我们想办法DP,可以设\(f[i][j]\)表示\(i\)这个位置起,后面P个站的是否有车的状态,1表示有,0表示没有,转移方程类似于:
\(f[i][j]+=f[i-1][k]\) 条件是\(j\)相比\(k\)只动了一辆车的先后顺序。
但是没这么简单,因为对于\((1,3),(2,4)\)这两个状态既可以从\((1,3),(2)\)转移来,也可以从\((1),(2,4)\)转移来,所以方案会算重,所以要强制要求只有一辆车可以动,这里强制只能动 \(i\),也就是说这个例子中只有 \(1\) 可以移动,就没问题了,因为每次只移动一位且转移相同,直接丢到矩阵里做n-k次即可,然后辅助矩阵的\((i,j)\)表示i这个状态可以转移到j,所以合法的话我们就赋值为1,对于\(i\)是否能转移到\(j\)\(check\),就是相当于\(i\)整体右移一位,并且除了第P位,其他位置要相同,只有多出来的位置可以不同.

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int mod=30031;
int n,m,p,f[233],cnt=0;
void dfs(int dep,int tot,int sum){
	if(sum==m){
		f[++cnt]=tot;
		return ;
	}
	if(dep==p+1)return ;
	dfs(dep+1,tot+(1<<(p-dep)),sum+1);
	dfs(dep+1,tot,sum);
}
struct mat{
	int a[141][141];
	mat(){memset(a,0,sizeof(a));}
	mat operator *(const mat &pr)const{
		mat tmp;
		for(int i=1;i<=cnt;i++)
			for(int j=1;j<=cnt;j++)
				for(int k=1;k<=cnt;k++){
					tmp.a[i][j]+=a[i][k]*pr.a[k][j]%mod;
					if(tmp.a[i][j]>=mod)tmp.a[i][j]-=mod;
				}
		return tmp;
	}
};
bool check(int x,int y){
	int tmp=(x-(1<<(p-1)))<<1;
	y^=tmp;if(y==(y&(-y)))return true;
	return false;
}
void work()
{
	scanf("%d%d%d",&n,&m,&p);
	dfs(2,1<<(p-1),1);
	mat T;
	for(int i=1;i<=cnt;i++)
		for(int j=1;j<=cnt;j++)
			if(check(f[i],f[j]))T.a[i][j]=1;
   mat S;
	for(int i=1;i<=cnt;i++)S.a[i][i]=1;
	n-=m;
	while(n){
		if(n&1)S=S*T;
		T=T*T;n>>=1;
	}
	printf("%d\n",S.a[1][1]);
	//为什么答案是这个?因为我的dfs顺序是这样的啊=.=
}
int main()
{
	work();
	return 0;
}


posted @ 2017-09-24 15:25  PIPIBoss  阅读(190)  评论(0编辑  收藏  举报