HNOI10 设计路线题解

it2026-03-18  5

【题目描述】城市有N个公交车站,排列在一条长为N-1公里的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1公里。按以下规则设计线路:1.设共有K辆公交车,则1到K号车站作为始发站,N-K+1到N号车站作为终点站。2.每个车站必须被一辆且仅一辆公交车经停(始发站和终点站也算被经停)。3.公交车只能从编号较小的车站驶向编号较大的车站。4.一辆公交车经停的相邻两个车站间的距离不得超过P公里。注意“经停”是指经过并停车,因经过不一定会停车,故经停与经过是两个不同的概念。现在想知道有多少种满足要求的方案。只需求出答案对30031取模的结果。【输入格式】只有一行,其中包含用空格隔开的三个正整数N,K,P,分别表示公交车站数,公交车数,一辆公交车经停的相邻两个车站间的最大距离。【输出格式】仅包含一个整数,表示满足要求的方案数对30031取模的结果。

【输入输出样例】input output样例一:10 33 1样例二:5 23 3样例三:10 24 81样例解释:样例一满足要求的方案只有1种,即:(1,4,7,10),(2,5,8),(3,6,9)。样例二满足要求的方案有3种,即:(1,3,5),(2,4);(1,3,4),(2,5)和(1,4),(2,3,5)。【数据规模】40%的数据满足N≤1000。100%的数据满足1<N<10^9,1<P≤10,K<N,1<K≤P

计数dp蒟蒻先给各位大神跪烂。

看到这个题的第一感觉就是没法下手(搜索没法骗分啊啊啊啊啊啊~~~~~)。

仔细看了看数据规模,发现了p和k的值都很小,感觉这肯定是一个重要条件。

经过分析以后,发现题目要求每个站都必须有公交车经停一次,如果与当前站的距离大于了p,且没有被经停,那么这个站就再也没有机会被经停了。

所以我们可以定义一个状态f[i][State]表示i以及之前的所有站都被经停,state表示i后面p个站哪些地方停了车。(并且保证i站有车停)

每次转移只考虑第i个站的公交车往哪里开就行了。

光是这样还不能通过此题,还要用矩阵快速幂来优化。

具体细节见标程:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int LIM=1<<11;const int MOD=30031;const int MAXN=140;int n,K,p;int State[MAXN],Cnt[LIM];int cnt,_,tmp;struct MATRIX{    int n,m;    int Matrix[MAXN][MAXN];    MATRIX(){        memset(Matrix,0,sizeof(Matrix));    }};MATRIX r,Ans;bool Check(int x){    int Ret=0;    while(x){        x-=x&-x;        Ret++;    }    return Ret==K;}MATRIX Mult(MATRIX a,MATRIX b){    MATRIX Ret;    Ret.n=a.n; Ret.m=b.m;    for(int i=1;i<=a.n;i++)        for(int j=1;j<=b.m;j++)            for(int k=1;k<=a.m;k++)                Ret.Matrix[i][j]=(Ret.Matrix[i][j]+a.Matrix[i][k]*b.Matrix[k][j])%MOD;    return Ret;}int main(){    scanf("%d%d%d",&n,&K,&p);    _=(1<<p)-1;    tmp=1<<(p-1);//保证最高位是1    for(int i=0;i<tmp;i++)        if(Check(tmp+i)){            State[++cnt]=tmp+i;            Cnt[tmp+i]=cnt;        }    int t;    r.n=cnt; r.m=cnt;    for(int i=1;i<=cnt;i++){        t=_&(State[i]<<1);        for(int j=1;j<=p;j++)            if(!((t>>(j-1))&1)&&(t+(1<<j-1))>=tmp)                r.Matrix[i][Cnt[t+(1<<j-1)]]++;    }    t=Cnt[((1<<K)-1)<<(p-K)];    Ans.Matrix[1][t]=1,Ans.n=1; Ans.m=cnt;    n-=K;    while(n){        if(n&1)            Ans=Mult(Ans,r);        n>>=1;        r=Mult(r,r);    }    printf("%d",Ans.Matrix[1][t]);    return 0;}

转载于:https://www.cnblogs.com/Return-0/archive/2013/03/18/2965460.html

相关资源:数据结构—成绩单生成器
最新回复(0)