[HNOI2010]公交线路

[HNOI2010]公交线路

不看题解不会做类型...
看到数据范围,显然要构造矩阵.
但是状态有那么多,于是要缩减状态.
\(dp[i][s]\)表示第i个车站和之后的p个车站,k辆车最后出没的位置.一辆车最多走p个车站,于是必定会在这p个车站出现至少一次,j就是一个长度为p的,含k个1的01串,最多有252种情况,转移只要在1之间转移就可以了,所以显然第一位没有车的状态可以缩掉.
每次转移只动一辆车,这样一步一步地走,不重不漏.转移矩阵构出来之后直接快速幂就可以了,最后要的状态是\(dp[n-k][(1<<k)-1]\)

#include<bits/stdc++.h>
#define mod 30031
using namespace std;
int n,k,p,s,f[20],st[505];
int lowbit(int x){return x&-x;}
int calc(int x){int r=0;for(int i=x;i>=1;i-=lowbit(i),r++);return r;}
struct matrix
{
    int a[150][150];
    int *operator [] (int i){return a[i];}
    matrix operator * (matrix x)
        {
            matrix y;memset(y.a,0,sizeof(y.a));
            for(int i=1;i<=s;i++)
                for(int j=1;j<=s;j++)
                    for(int k=1;k<=s;k++)
                        y[i][j]+=a[i][k]*x[k][j]%mod,y[i][j]%=mod;
            return y;
        }
}A,B;
void ksm(int k)
{
    for(int i=1;i<=s;i++)A[i][i]=1;
    while(k){if(k&1)A=A*B;k>>=1;B=B*B;}
}
int main()
{
    cin>>n>>k>>p;//状态记录的是k辆车在i往后p个站点的最后出没点
    for(int i=0;i<(1<<p);i++)//合法状态是第1个位置有车,区间里一定是k个最后出没点
        if(calc(i)==k&&(i&1))st[++s]=i;
    for(int i=1;i<=s;i++)
        for(int j=1;j<=s;j++)
            if(calc((st[i]>>1)&st[j])==k-1)B[i][j]=1;
    ksm(n-k);
    cout<<A[1][1]<<endl;
    return 0;
}

posted @ 2018-10-22 22:40  Brioche  阅读(201)  评论(0编辑  收藏  举报