zoukankan      html  css  js  c++  java
  • BZOJ2004: [Hnoi2010]Bus 公交线路

    2004: [Hnoi2010]Bus 公交线路

    Time Limit: 20 Sec  Memory Limit: 259 MB
    Submit: 747  Solved: 512
    [Submit][Status][Discuss]

    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

    思路{
      P,K小得不行,想到了状态压缩。n的范围如此之大,考虑矩阵快速幂!
      先从简单的状态压缩开始。设$dp[i][j]$为强制选第i号停车,从第i号开始的后面p个的停车状态。转移。
      发现一个问题(1->3,2->4)和(2->4,1->3)属于同一种情况,所以我们只需要考虑dp[i-1]->dp[i]。
      关键就是后面状态j的转移关系了。发现dp[i-1][j']->dp[i][j]满足j'变成j时实际位置对应的状态中的二进制数的位数+1
      那么先删去i-1位置的数,j'-=(1<<(p-1)),然后j'<<1,变成对应的位置,由于j'->j时只有一个相对位置发生了变化,那么j'^=j,判断j'的二进制数中1的个数是否为1即可。
      那么转移方程就出来了。考虑构造矩阵。
      暴力构造矩阵的话大小是(2^p)^2的显然不行,我们只需考虑后面的p位中有k位有车的状态,不妨先DFS找出所有的状态,然后两两枚举即可。注意转移关系在矩阵中对应的位置
      不难发现构造的矩阵大小是(C(p-1,k-1))的,那这个就很对了。
      所以总的复杂度是O(logn*C(p-1,k-1)^3+p!)的。
    }

    #include<bits/stdc++.h>
    #define ll long long
    #define RG register
    #define il inline
    #define N 200
    #define mod 30031
    using namespace std;
    int n,k,p,que[N];
    struct matrix{
      int n,m;
      ll ma[N][N];
      void clear(){memset(ma,0,sizeof(ma));n=m=0;}
      matrix operator *(const matrix & a)const {
        matrix c;c.clear();
        c.n=n,c.m=a.m;
        for(int i=1;i<=c.n;++i){
          for(int j=1;j<=c.m;++j){
    	for(int k=1;k<=m;++k){
    	  c.ma[i][j]+=ma[i][k]*a.ma[k][j];
    	}
    	(c.ma[i][j]+=mod)%=mod;
          }
        }
        return c;
      }
    };
    matrix qp(matrix a,ll b){
      if(b==1)return a;if(b==2)return a*a;
      matrix tmp=qp(a,(b>>1));
      tmp=tmp*tmp;
      if(b&1)tmp=tmp*a;
      return tmp;
    }
    void dfs(int pos,int num,int cnt){
      if(cnt==k){que[++que[0]]=num;return;}
      for(int i=pos-1;i!=-1;i--)
        dfs(i,num+(1<<i),cnt+1);
    }
    #define lowbit(o) ( (o) & (-o) )
    bool check(int x,int y){
      int Temp=x-(1<<(p-1));
      Temp<<=1;Temp^=y;
      if(Temp==lowbit(Temp))return 1;
      return 0;
    }
    int main(){
      scanf("%d%d%d",&n,&k,&p);
      dfs(p-1,(1<<(p-1)),1);
      matrix temp;temp.clear();temp.n=temp.m=que[0];
      matrix ans;ans.clear();ans.ma[1][1]=1;ans.n=que[0],ans.m=1;
      for(int i=1;i<=que[0];++i){
        for(int j=1;j<=que[0];++j){
          if(check(que[i],que[j]))temp.ma[j][i]=1;
        }
      }
      temp=qp(temp,n-k);
      ans=temp*ans;
      cout<<ans.ma[1][1];
      return 0;
    }
    
  • 相关阅读:
    第八周作业
    第八周上机练习
    第七周作业
    第七次上机练习
    第六周作业
    4.9上机作业
    第五周作业
    第四次JAVA作业
    第四周作业
    第十六次作业
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7593834.html
Copyright © 2011-2022 走看看