[HNOI2010 公交路线]

[关键字]:数学 矩阵乘法

[题目大意]:有n个车站,k路车。每个车站只能被一路车停,且同一路车的相邻的两站之间不能超过p,求方案数。

//===============================================================================================================================

[分析]:首先因为同一路车的相邻的两站之间不能超过p,所以除前k个每p车站内都要有所有的公交车。这样可以p个p个的转移,用状态压缩dp,p中第一位必须被一辆车占所以方案数一共有c(9,4)=126个。首先处理出所有的合法状态,将这些状态之间的转移构造成矩阵,然后利用矩阵乘法优化加速。

[代码]:

View Code
#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<algorithm>

using namespace std;



const int MOD=30031;



struct node

{

    int n,m;

    int dat[131][131];

    friend node operator * (node a,node b)

    {

        node c;

        c.n=a.n,c.m=b.m;

        memset(c.dat,0,sizeof(c.dat));

        for (int i=1;i<=a.n;++i)

            for (int j=1;j<=b.m;++j)

                for (int k=1;k<=a.m;++k)

                    c.dat[i][j]=(c.dat[i][j]+a.dat[i][k]*b.dat[k][j])%MOD;

        return c;

    }

}ans,g;

int n,k,p,x,y,sum;

int a[131],b[1200];



bool Cleck(int x)

{

    int sum=0;

    while (x)

    {

        if (x%2) ++sum; 

        x/=2;

    }

    return sum==k;

}



void Make()

{

    g.n=sum,g.m=sum;

    for (int i=1;i<=sum;++i)

    {

        int z=x&(a[i]<<1);

        for (int j=1;j<=p;++j)

            if (!((z>>(j-1))&1) && (z+(1<<(j-1)))>=y)

                ++g.dat[i][b[z+(1<<(j-1))]];

    }

}



void Init()

{

    scanf("%d%d%d",&n,&k,&p);

    x=(1<<p)-1,y=1<<(p-1);

    for (int i=0;i<y;++i)

        if (Cleck(y+i)) a[++sum]=y+i,b[y+i]=sum;

    /*for (int i=1;i<=sum;++i)

        printf("%d\n",a[i]);*/

    Make();

    /*for (int i=1;i<=sum;++i)

    {

        for (int j=1;j<=sum;++j)

            printf("%d ",g.dat[i][j]);

        printf("\n");

    }*/

}



void Solve()

{

    int z=b[((1<<k)-1)<<(p-k)];

    //printf("%d\n",z);

    ans.n=1,ans.m=sum;

    ans.dat[1][z]=1;

    n-=k;

    while (1)

    {

        if (n&1) ans=ans*g;

        n>>=1;if (!n) break;

        g=g*g;

    }

    printf("%d\n",ans.dat[1][z]);

}



int main()

{

    Init();

    Solve();

    return 0;

}

你可能感兴趣的:(公交)