[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取模的结果。
输入输出样例
说明
【样例说明】
样例一的可行方案如下: (1,4,7,10),(2,5,8),(3,6,9)
样例二的可行方案如下: (1,3,5),(2,4) (1,3,4),(2,5) (1,4),(2,3,5)
P<=10 , K <=8
原条件可以转化为任意长为p的连续车站有k种车
于是状压,令f[i][S],表示前i个车站,前p个车站状态为S
状态为S的第j位为1表示从i开始,表示那一位是那一种车最靠近i的车站
那么S为合法的条件为有且只有k位为1
构造转移矩阵,矩阵快速幂
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 struct Matrix 8 { 9 int a[131][131]; 10 }Mat,ans,res; 11 int cnt,Mod=30031,n,k,p,c[2001],w[2001],s[2001]; 12 Matrix operator*(const Matrix &a,const Matrix &b) 13 {int i,j,l; 14 Matrix res; 15 memset(res.a,0,sizeof(res.a)); 16 for (i=1;i<=cnt;i++) 17 { 18 for (j=1;j<=cnt;j++) 19 { 20 for (l=1;l<=cnt;l++) 21 { 22 res.a[i][j]+=a.a[i][l]*b.a[l][j]%Mod; 23 if (res.a[i][j]>=Mod) 24 res.a[i][j]-=Mod; 25 } 26 } 27 } 28 return res; 29 } 30 Matrix qpow(int y) 31 {int i; 32 for (i=1;i<=cnt;i++) 33 res.a[i][i]=1; 34 while (y) 35 { 36 if (y&1) res=res*Mat; 37 Mat=Mat*Mat; 38 y>>=1; 39 } 40 return res; 41 } 42 int main() 43 {int i,j,x; 44 cin>>n>>k>>p; 45 c[0]=0; 46 for (i=1;i<(1<<p);i++) 47 { 48 c[i]=c[i-(i&(-i))]+1; 49 if (c[i]==k&&(i&(1<<p-1))) 50 { 51 w[i]=++cnt; 52 s[cnt]=i; 53 } 54 } 55 for (i=1;i<=cnt;i++) 56 { 57 if (s[i]&1) 58 { 59 Mat.a[i][w[(s[i]>>1)|(1<<p-1)]]=1; 60 } 61 else 62 { 63 for (j=0;j<p;j++) 64 if (s[i]&(1<<j)) 65 { 66 Mat.a[i][w[((s[i]^(1<<j))>>1)|(1<<p-1)]]=1; 67 } 68 } 69 } 70 x=(1<<p)-(1<<(p-k)); 71 ans.a[1][w[x]]=1; 72 ans=ans*qpow(n-k); 73 printf("%d\n",ans.a[1][w[x]]); 74 }