Description
小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km。 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路:
1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站。
2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过)。
3.公交车只能从编号较小的站台驶往编号较大的站台。
4.一辆公交车经过的相邻两个
站台间距离不得超过Pkm。 在最终设计线路之前,小Z想知道有多少种满足要求的方案。由于答案可能很大,你只需求出答案对30031取模的结果。
Input
仅一行包含三个正整数N K P,分别表示公交车站数,公交车数,相邻站台的距离限制。
N<=10^9,1<P<=10,K<N,1<K<=P
Output
仅包含一个整数,表示满足要求的方案数对30031取模的结果。
Sample Input
样例一:10 3 3
样例二:5 2 3
样例三:10 2 4
样例二:5 2 3
样例三:10 2 4
Sample Output
1
3
81
3
81
HINT
【样例说明】
样例一的可行方案如下: (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
Solution
显然这个范围是要状压+矩乘……然后我就不会了
因为一个公交车经过的两个相邻的站台之间的距离不超过$p$,所以设$f[i][S]$表示最靠左的车在$i$位置,$i$后面$p$个位置的状态是$S$,其中$S$的某一位是0代表没车,1代表有车。
这相当于我们把这$k$辆车都放到一个长度为$p$的区间内来做。因为车没有编号所以我们并不需要区分。
然后状态数最大只有$C(9,4)$,所以可以预处理出所有状态可以到达的状态然后矩阵转移……$f[i][S]=sum f[i-1][S']$,其中$S'$状态可以转移到$S$。
初始状态为长度为$p$的区间左边一段都是1,终止状态也是。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define MOD (30031) 5 using namespace std; 6 7 int n,k,p,S[209],cnt,Refun; 8 9 struct Matrix 10 { 11 int m[209][209]; 12 Matrix(){memset(m,0,sizeof(m));} 13 Matrix operator * (const Matrix b) const 14 { 15 Matrix ans; 16 for (int i=1; i<=130; ++i) 17 for (int j=1; j<=130; ++j) 18 for (int k=1; k<=130; ++k) 19 (ans.m[i][j]+=m[i][k]*b.m[k][j])%=MOD; 20 return ans; 21 } 22 }A,G; 23 24 Matrix Qpow(Matrix a,int p) 25 { 26 Matrix ans; 27 for (int i=1; i<=130; ++i) ans.m[i][i]=1; 28 while (p) 29 { 30 if (p&1) ans=ans*a; 31 a=a*a; p>>=1; 32 } 33 return ans; 34 } 35 36 int Get(int x)//二进制下1的数量 37 { 38 int num=0; 39 while (x) num+=(x&1),x>>=1; 40 return num; 41 } 42 43 bool check(int x,int y)//判断x状态是否能到达y状态 44 { 45 int now=S[x]<<1, tmp=0; 46 for (int i=0; i<p; ++i) 47 if ((now&(1<<i))!=(S[y]&(1<<i))) tmp++; 48 return tmp<=1; 49 } 50 51 int main() 52 { 53 scanf("%d%d%d",&n,&k,&p); 54 for (int i=1<<(p-1); i<=(1<<p)-1; ++i)//强制第一位有车 55 if (Get(i)==k) 56 { 57 S[++cnt]=i; 58 if (S[cnt]==(1<<p)-(1<<p-k)) Refun=cnt;//记录车都在起点/终点的状态 59 } 60 A.m[1][Refun]=1; 61 for (int i=1; i<=cnt; ++i) 62 for (int j=1; j<=cnt; ++j) 63 if (check(i,j)) G.m[i][j]=1; 64 G=Qpow(G,n-k); 65 A=A*G; 66 printf("%d ",A.m[1][Refun]); 67 }