• [HNOI2010]Bus 公交线路


    Description
    小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km。
    作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路:

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

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

    Input
    仅一行包含三个正整数N K P,分别表示公交车站数,公交车数,相邻站台的距离限制。
    N<=10^9,1<P<=10,K<N,1<K<=P

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

    Sample Input 1
    10 3 3

    Sample Output 1
    1

    Sample Input 2
    5 2 3

    Sample Output 2
    3

    Sample Input 3
    10 2 4

    Sample Output 3
    81


    看到(pleqslant 10),这题肯定要状压;看到(nleqslant 10^9),这题肯定要矩阵乘法

    (f[i][sta])表示最快的公交车到了第(i)个车站,当前停靠公交车的站台的状态为(sta)((sta)上第(k)位为1说明第(k)个车站上停了车),很容易推出转移方程式为(f[i][sta]=sumlimits_{j=k}^{i-1}f[j][sta'])(sta')(sta)的转移是合法的。

    然后注意到题目有限制:一个公交车经过的两个相邻的站台之间的距离不超过(p),这样可以把(sta)的枚举范围从([1,2^n-1])缩小到([1,2^p-1]),那么空间上就没啥问题了。

    然后我们发现对于每个(f[i][sta])来说,拿来转移到它的(sta')都是一样的,那么我们可以用矩乘优化来加速这个DP

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    #define lowbit(x) ((x)&(-x))
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x>=10)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1.5e2,MOD=30031;
    int n,k,p,tot;
    struct Matrix{
    	int v[N+10][N+10];
    	Matrix(){memset(v,0,sizeof(v));}
    	void init(){for (int i=1;i<=tot;i++)	v[i][i]=1;}
    }trans,Ans;
    Matrix operator *(const Matrix &x,const Matrix &y){
    	Matrix z;
    	for (int i=1;i<=tot;i++)
    		for (int j=1;j<=tot;j++)
    			for (int k=1;k<=tot;k++)
    				z.v[i][k]=(z.v[i][k]+x.v[i][j]*y.v[j][k])%MOD;
    	return z;
    }
    Matrix mlt(Matrix a,int b){
    	Matrix res; res.init();
    	for (;b;b>>=1,a=a*a)	if (b&1)	res=res*a;
    	return res;
    }
    int calc(int x){
    	int res=0;
    	while (x) res++,x-=lowbit(x);
    	return res;
    }
    bool check(int Now,int To){
    	Now<<=1;
    	int tmp=0;
    	for (int i=0;i<p;i++)	if ((Now&(1<<i))^(To&(1<<i)))	tmp++;
    	return tmp<2;
    }
    int stack[(1<<10)+10];
    int main(){
    	n=read(),k=read(),p=read();
    	int Endl=0;
    	for (int sta=(1<<(p-1));sta<1<<p;sta++){
    		if (calc(sta)==k){
    			stack[++tot]=sta;
    			if (sta==(1<<p)-(1<<(p-k)))	Endl=tot;
    		}
    	}
    	for (int i=1;i<=tot;i++)
    		for (int j=1;j<=tot;j++)
    			if (check(stack[i],stack[j]))
    				trans.v[i][j]=1;
    	Ans.v[1][Endl]=1;
    	Ans=Ans*mlt(trans,n-k);
    	printf("%d
    ",Ans.v[1][Endl]);
    	return 0;
    }
    
  • 相关阅读:
    页面渲染1——创建对象模型
    HTTP 缓存
    web安全字体
    图片优化
    基于文本内容的压缩
    Mac homebrew的熟悉和常用指令
    二、Java注释
    一、Java环境变量配置
    JS中的逻辑运算符&&、||
    js 中的 深拷贝与浅拷贝
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9690165.html
Copyright © 2020-2023  润新知