bzoj 2004 【hnoi2010】公交线路

来源:互联网 发布:ug8.5数控编程视频教程 编辑:程序博客网 时间:2024/04/30 21:56
时间限制:1秒  内存限制:64M

【问题描述】

  小 Z 所在的城市有 N 个公交车站,排列在一条长为 N-1 公里的直线上,从左到右依次编号为 1 到 N,相邻公交车站间的距离均为 1 公里。

  作为公交车线路的规划者,小 Z 调查了市民的需求,决定按以下规则设计线路:

  1.设共有 K 辆公交车,则 1 到 K 号车站作为始发站, N-K+1 到 N 号车站作为终点站。
  2.每个车站必须被一辆且仅一辆公交车经停(始发站和终点站也算被经停)。
  3.公交车只能从编号较小的车站驶向编号较大的车站。
  4.一辆公交车经停的相邻两个车站间的距离不得超过 P 公里。

  注意“经停”是指经过并停车, 因经过不一定会停车,故经停与经过是两个不同的概念。

  在最终确定线路之前,小 Z 想知道有多少种满足要求的方案。由于答案可能很大,你只需求出答案对 30031 取模的结果。

【输入格式】

  只有一行,其中包含用空格隔开的三个正整数N, K,P, 分别表示公交车站数,公交车数, 一辆公交车经停的相邻两个车站间的最大距离。

【输出格式】

  仅包含一个整数,表示满足要求的方案数对 30031 取模的结果。

【输入样例】

【样例1】
 10 3 3

【样例2】
 5 2 3

【样例3】
 10 2 4

【输出样例】

【样例1】
 1

【样例2】
 3

【样例3】
 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 ≤1 0, K < N, 1 < K ≤ P

【来源】

bzoj 2004

一道极其坑的题,开始想了好久都没有思路。

先说一下我看到这道题的第一反应吧:
1.p<=10 一定是状态压缩用的。
2.n<=1*10^9 作为一道递推绝对要用矩阵优化。

然后我就卡死了,推了好久才得出的方程。
d[i][A]:前i个站最后p个站的n辆车最后停的位置为A(停了的2进制位就为1)的方案数。(最后一个站必须有车停)

转移的时候我们强制第一个先走,走一步(不然会重)。这样就可以得出哪些情况之间可以转移了。我们就可以矩阵优化了。

答案就是最后n个站都有车停的情况。

代码如下:

#include<cstdlib>#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int maxn=150;const int mod=30031;struct mat{    int n,m,v[maxn][maxn];    mat()    {        memset(v,0,sizeof(v));        m=n=0;    }    friend mat operator * (mat a,mat b)    {        mat c;        c.m=a.n;c.n=b.m;        for(int i=1;i<=c.m;i++)        for(int j=1;j<=b.m;j++)        for(int k=1;k<=a.m;k++)        c.v[i][j]=(c.v[i][j]+a.v[i][k]*b.v[k][j])%mod;        return c;    }}a,B;int g[maxn],top=0,n,m,p,b[maxn],ans;int work(int x){    int t=0;    while(x)    {        t++;        x-=(x&(-x));    }    return t;}bool check(int i,int j){    int x=g[i],y=g[j];    x=x<<1;    x-=b[p+1];    x=x^y;    return x-(x&(-x))==0;}mat qkpow(mat a,int x){    mat t,c;    c.m=c.n=a.m;    for(int i=1;i<=c.m;i++) c.v[i][i]=1;    t=a;    while(x)    {        if (x&1) c=c*t;        x=x>>1;        t=t*t;    }    return c;}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    scanf("%d%d%d",&n,&m,&p);    b[1]=1;for(int i=2;i<=p+1;i++) b[i]=b[i-1]<<1;    for(int i=b[p];i<=b[p+1]-1;i++)    if(work(i)==m)    {        g[++top]=i;        if(i==b[p+1]-b[p-m+1])  ans=top;    }    a.m=a.n=top;    for(int i=1;i<=top;i++)    for(int j=1;j<=top;j++)    if(check(i,j)) a.v[j][i]=1;    B.n=top,B.m=1;    B.v[ans][1]=1;    B=qkpow(a,n-m)*B;    printf("%d\n",B.v[ans][1]);    return 0;}
1 0
原创粉丝点击