bzoj2004 [Hnoi2010]公交线路

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

Sample Output

1
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
 
正解:状压$dp$+矩阵快速幂优化。
以前考过,当时什么都不会,现在看来还是不难吧。。
不过一直在想矩阵快速幂会$T$啊,结果就被告知状态数其实很少,可以把它离散化(差不多这意思吧)。。
所以大概就是设$f[i][j]$表示到了第$i$个站,所有公交车离这个车站的距离的状态为$j$,这个转移是暴力的。
乍一看,$j$可以取$[0,2^{p}-1]$这么多状态,但是我们可以发现,每次都有一个公交车与这个车站的距离为$0$,所以我们状态数可以$/2$。
然后我们又可以发现,$j$里面一定有$k-1$个$1$,那么我们算一下$\binom{p-1}{k-1}$,发现最大只有$\binom{9}{4}=126$。
于是我们把这些状态压到一个数组里,如果$i$状态可以转移到$j$状态,那么转移矩阵的$[i][j]$这个位置就可以赋为$1$。
那么初始状态是$f[k][2^{p}-2]=1$,乘上转移矩阵的$n-k$次方,找到$f[n][2^{p}-2]$就是答案了。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define rhl (30031)
 6 
 7 using namespace std;
 8 
 9 struct data{ int m[130][130]; }a,b;
10 
11 int st[130],n,k,p,sz,now;
12 
13 il int gi(){
14   RG int x=0,q=1; RG char ch=getchar();
15   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
16   if (ch=='-') q=-1,ch=getchar();
17   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
18   return q*x;
19 }
20 
21 il int calc(RG int s){
22   RG int res=0; while (s) res+=s&1,s>>=1; return res;
23 }
24 
25 il int can(RG int i,RG int j){
26   RG int x;
27   if (st[i]>>(p-1)&1){
28     x=(st[i]^(1<<(p-1)))<<1;
29     return (x|2)==st[j];
30   }
31   if ((st[i]<<1)==st[j]) return 1;
32   for (RG int s=0;s<p;++s)
33     if (st[i]>>s&1){
34       x=(st[i]^(1<<s))<<1;
35       if ((x|2)==st[j]) return 1;
36     }
37   return 0;
38 }
39 
40 il data mul(data a,data b){
41   data c;
42   for (RG int i=1;i<=sz;++i)
43     for (RG int j=1;j<=sz;++j){
44       c.m[i][j]=0;
45       for (RG int k=1;k<=sz;++k)
46     (c.m[i][j]+=a.m[i][k]*b.m[k][j])%=rhl;
47     }
48   return c;
49 }
50 
51 il data qpow(data a,RG int b){
52   data ans=a; --b;
53   while (b){
54     if (b&1) ans=mul(ans,a);
55     a=mul(a,a),b>>=1;
56   }
57   return ans;
58 }
59 
60 int main(){
61 #ifndef ONLINE_JUDGE
62   freopen("bus.in","r",stdin);
63   freopen("bus.out","w",stdout);
64 #endif
65   cin>>n>>k>>p;
66   for (RG int s=0;s<(1<<p);++s)
67     if (!(s&1) && calc(s)==k-1) st[++sz]=s;
68   for (RG int i=1;i<=sz;++i)
69     for (RG int j=1;j<=sz;++j)
70       if (can(i,j)) b.m[i][j]=1;
71   for (RG int i=1;i<=sz;++i)
72     if (st[i]+1==(1<<k)-1) a.m[1][now=i]=1;
73   b=qpow(b,n-k),a=mul(a,b);
74   cout<<a.m[1][now]; return 0;
75 }

 

posted @ 2017-09-15 20:11  wfj_2048  阅读(252)  评论(0编辑  收藏  举报