[BZOJ2004] [Hnoi2010]Bus 公交线路

[BZOJ2004] [Hnoi2010]Bus 公交线路

\(n\)\(10^9\)了,还不矩阵吗?

\(dp[S]\)表示前\(p\)位哪些点放了车并且要保证每个点都被经过了一次

每次转移就是从前面的点里选一辆车跑过来,并且保证第一位没有车留下来

状态\(2^{10}\)?

不过状态显然保证\(popcount(S)==k\)

状态最多其实是\(C_{10}^{5}=252\) 所以可以跑矩阵

可能有点卡常,不过应该还可以优化,我没有加优化

 
bool be;
 
int n,p,k;
 
int dp[1<<10];
int cnt[1<<10];
int tmp[1<<10];
int A;
 
 
int st[300],sc,id[1<<10];
int f[1][300],ans[1][300];
 
 
int B;
 
 
struct Mat{
    int a[300][300];
    void init(){ memset(a,0,sizeof a); }
    void Get1(){ rep(i,1,sc) a[i][i]=1; }
    Mat operator * (const Mat x) const {
        Mat res;
        for(reg int i=1;i<=sc;++i) {
            for(reg int j=1;j<=sc;++j) {
                ll t=0;
                for(reg int o=1;o<=sc;++o) t+=a[i][o]*x.a[o][j];
                res.a[i][j]=t%P;
            }
        }
        return res;
    }
}res,x;
 
 
 
 
void Solve(){
    A=(1<<p)-1;
    rep(i,1,A) cnt[i]=cnt[i&(i-1)]+1;
    rep(S,0,A) if(cnt[S]==k) ++sc,id[st[sc]=S]=sc;
    rep(S,0,A) if(cnt[S]==k) {
        if(S&1) {
            x.a[id[S]][id[(S>>1)|(1<<(p-1))]]++;
        } else {
            rep(i,0,p-1) if(S&(1<<i)) {
                int NS=((S^(1<<i))>>1)|(1<<(p-1));
                x.a[id[S]][id[NS]]++;
            }
        }
    }
    int T=0;
    for(reg int j=p-1;j>=p-k;j--) T|=1<<j;
    f[0][id[T]]=1;
    res.Get1();
    n-=k;
    int t=n;
    while(t) {
        if(t&1) res=res*x;
        x=x*x;
        t>>=1;
    }
    rep(i,0,0) rep(j,1,sc) rep(o,1,sc) (ans[i][o]+=f[i][j]*res.a[j][o])%=P;
    T=0;
    rep(j,p-k,p-1) T|=1<<j;
    printf("%d\n",ans[0][id[T]]);
}
 
bool ed;
 
int main(){
    //printf("%.2lf\n",(&ed-&be)/1024.0/1024.0);
    n=rd(),k=rd(),p=rd();
    Solve();
}
 
 
 
 
 
posted @ 2019-10-13 10:11  chasedeath  阅读(110)  评论(0编辑  收藏  举报