zoukankan      html  css  js  c++  java
  • 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$,那么我们算一下$inom{p-1}{k-1}$,发现最大只有$inom{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 }
  • 相关阅读:
    static生命周期
    VS2008 JS调试和Silverlight 后台代码调试 相互影响的问题。自己做实例证明
    思考记跳出以往的自己
    javascript setAttribute使用方法 查缺补漏
    克服浮躁,踏实工作,控制自我
    DES加密GUID+文件名称,关于DES加密后文件长度是否超过WINDOWS文件命名规定长度255个字节。
    阅读WPF揭秘前两章探索Silverlight运行的基本原理和RIA工作流程的密码()
    Silverlight运行原理经典问答。
    HTML 实用标签 (你不知道的HTML)
    ASP.NET项目整合 (Silverlight 和 WEB Service ) 过程及原理
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7528232.html
Copyright © 2011-2022 走看看