BZOJ 2004 Bus 公交线路(矩阵)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2004

题意:小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km。 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路:(1)设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站。 (2)每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过)。(3)公交车只能从编号较小的站台驶往编号较大的站台。 (4)一辆公交车经过的相邻两个站台间距离不得超过Pkm。在最终设计线路之前,小Z想知道有多少种满足要求的方案。由于答案可能很大,你只需求出答案对30031取模的结果。

思路:用f[i][st]表示从i位置向后连续的p(i,i+1,……,i+p-1)个位置的状态为st的方案数,规定i位置必须为1.转移的时候每次i位置的1向后转移。开始状态和结束状态均为m个1,令S=2^m-1,则开始状态为f[1][S]=1,则答案为f[n-m+1][S]。所以求转移矩阵的n-m次方即可。

 








int num;


struct Matrix
{
    int a[205][205];
    
    void init(int x)
    {
        clr(a,0);
        int i;
        if(x) FOR0(i,205) a[i][i]=1;
    }
    
    
    Matrix operator*(Matrix p)
    {
        Matrix ans;
        ans.init(0);
        int i,j,k;
        FOR0(k,num) FOR0(i,num) FOR0(j,num)
        {
            ans.a[i][j]+=a[i][k]*p.a[k][j]%mod;
            ans.a[i][j]%=mod;
        }
        return ans;
    }
    
    Matrix Pow(int n)
    {
        Matrix ans,p=*this;
        ans.init(1);
        while(n>0)
        {
            if(n&1) ans=ans*p;
            p=p*p;
            n>>=1;
        }
        return ans;
    }
};


Matrix a,b;
int st[N],mp[N],n,m,p;


int ok(int st)
{
    if(st%2==0) return 0;
    int cnt=0,i;
    FOR0(i,p) if(st&(1<<i)) cnt++;
    return cnt==m;
}


int main()
{
    clr(mp,-1);
    RD(n,m,p);
    int i,j;
    FOR0(i,(1<<p)) if(ok(i)) 
    {
        st[num]=i,mp[i]=num++;
    }
    int x,y,z;
    FOR0(i,num)
    {
        x=st[i];
        y=x/2;
        FOR0(j,p) 
        {
            z=mp[y|(1<<j)];
            if(z!=-1) a.a[i][z]=1;
        }
    }
    b.init(0);
    b.a[0][mp[(1<<m)-1]]=1;
    b=b*a.Pow(n-m);
    PR(b.a[0][mp[(1<<m)-1]]);
}

你可能感兴趣的:(ZOJ)