[BZOJ]2004: [Hnoi2010]Bus 公交线路 状态压缩DP+矩阵乘法
2017-08-22 15:43
477 查看
Description
小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距
离均为1km。 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路:
1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站。
2.每个车站必须被一辆且仅一辆公交车经过(始发站和
终点站也算被经过)。
3.公交车只能从编号较小的站台驶往编号较大的站台。
4.一辆公交车经过的相邻两个
站台间距离不得超过Pkm。 在最终设计线路之前,小Z想知道有多少种满足要求的方案。由于答案可能很大,你只
需求出答案对30031取模的结果。
Input
仅一行包含三个正整数N K P,分别表示公交车站数,公交车数,相邻站台的距离限制。
N<=10^9,1
发博客存一存矩阵乘法快速幂的模板,顺便为一些新手朋友,不太会矩阵乘法的,提供一份没有矩阵乘法的DP代码。
小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距
离均为1km。 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路:
1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站。
2.每个车站必须被一辆且仅一辆公交车经过(始发站和
终点站也算被经过)。
3.公交车只能从编号较小的站台驶往编号较大的站台。
4.一辆公交车经过的相邻两个
站台间距离不得超过Pkm。 在最终设计线路之前,小Z想知道有多少种满足要求的方案。由于答案可能很大,你只
需求出答案对30031取模的结果。
Input
仅一行包含三个正整数N K P,分别表示公交车站数,公交车数,相邻站台的距离限制。
N<=10^9,1
题解:
这篇博客写得很好:FYC神犇发博客存一存矩阵乘法快速幂的模板,顺便为一些新手朋友,不太会矩阵乘法的,提供一份没有矩阵乘法的DP代码。
AC代码:
#include<cstdio> #include<cstring> #include<iostrea 4000 m> #include<algorithm> using namespace std; const int mod=30031; int n,k,p,list[130],len=0; struct matrix{int v[130][130],x,y;}A; matrix operator * (matrix a,matrix b) { matrix c;c.x=a.x;c.y=b.y; for(int i=1;i<=c.x;i++) for(int j=1;j<=c.y;j++) { c.v[i][j]=0; for(int k=1;k<=a.y;k++) c.v[i][j]+=a.v[i][k]*b.v[k][j],c.v[i][j]%=mod; } return c; } int one(int x) { int re=0; while(x) { re+=(x&1); x>>=1; }return re; } bool can(int to,int from) //检查状态from能否一步转移到状态to { from=(from-(1<<(p-1)))<<1; //这一步相当于把from向左推了一位,个位用0补齐 int tmp=from^to; //tmp应该只有一个1 if(tmp==(tmp&(-tmp))) return true; //tmp只有一个1,则是合法的 return false; //否则是不合法的 } void print(int x) { if(x==0)return; print(x>>1); printf("%d",x&1); } void pre() { for(int i=0;i<=((1<<k)-1)<<(p-k);i++) if(one(i)==k&&i>=(1<<(p-1)))list[++len]=i; for(int i=1;i<=len;i++) for(int j=1;j<=len;j++) { if(can(list[j],list[i]))A.v[i][j]=1; else A.v[i][j]=0; } A.x=A.y=len; } matrix Pow(matrix x,int y) { if(y==1)return x; matrix t=Pow(x,y>>1),ans=t*t; if(y&1)ans=ans*x; return ans; } int main() { scanf("%d%d%d",&n,&k,&p); pre(); matrix ans1,ans2; ans1.x=1;ans1.y=len; for(int j=1;j<ans1.y;j++)ans1.v[1][j]=0; ans1.v[1][len]=1; ans2=Pow(A,n-k); ans2=ans1*ans2; printf("%d",ans2.v[1][len]); }
普通DP代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,k,p,f[2][130],now=1; //k是车的数量 p是距离限制 void print(int x) { if(x==0)return; print(x>>1); printf("%d",x&1); } int one(int x) { int re=0; while(x) { re+=(x&1); x>>=1; }return re; } bool can(int to,int from) //检查状态from能否一步转移到状态to { from=(from-(1<<(p-1)))<<1; //这一步相当于把from向左推了一位,个位用0补齐 int tmp=from^to; //tmp应该只有一个1 if(tmp==(tmp&(-tmp))) return true; //tmp只有一个1,则是合法的 return false; //否则是不合法的 } int main() { memset(f,0,sizeof(f)); scanf("%d%d%d",&n,&k,&p); f[1][((1<<k)-1)<<(p-k)]=1; for(int i=2;i<=n-k+1;i++) { now^=1; memset(f[now],0,sizeof(f[now])); for(int j=0;j<=((1<<k)-1)<<(p-k);j++) { if(j>=(1<<(p-1))&&one(j)==k) { for(int l=0;l<=((1<<k)-1)<<(p-k);l++) if(l>=(1<<(p-1))&&one(l)==k&&can(l,j)) { f[now][l]+=f[now^1][j]; f[now][l]%=30031; } } } } printf("%d",f[now][((1<<k)-1)<<(p-k)]); }
相关文章推荐
- BZOJ 2004|HNOI 2010 Day 1|公交线路|状态压缩动态规划|矩阵乘法
- [BZOJ 2004] [Hnoi2010] Bus 公交线路 【状压DP + 矩阵乘法】
- 【BZOJ2004】[Hnoi2010]Bus 公交线路 状压+矩阵乘法
- bzoj 2004: [Hnoi2010]Bus 公交线路 状压dp+矩阵乘法
- BZOJ 2004: [Hnoi2010]Bus 公交线路 [DP 状压 矩阵乘法]
- 【bzoj2004】[Hnoi2010]Bus 公交线路 状压dp+矩阵乘法
- BZOJ 2004: [Hnoi2010]Bus 公交线路
- [BZOJ2004][Hnoi2010]Bus 公交线路(状压DP+矩阵乘法)
- 【bzoj2004】[Hnoi2010]Bus 公交线路
- 【BZOJ】2004: [Hnoi2010]Bus 公交线路 状压DP+矩阵快速幂
- bzoj 2004: [Hnoi2010]Bus 公交线路
- 【bzoj2004】[Hnoi2010]Bus 公交线路
- BZOJ2004: [Hnoi2010]Bus 公交线路
- bzoj 2004[Hnoi2010]Bus 公交线路
- 【HNOI2010】【BZOJ2004】Bus 公交线路
- 【BZOJ 2004】: [Hnoi2010]Bus 公交线路
- [BZOJ2004][Hnoi2010]Bus 公交线路
- bzoj 2004: [Hnoi2010]Bus 公交线路
- [BZOJ 2004][HNOI 2010]Bus 公交线路(矩阵快速幂加速DP)
- BZOJ 2004 [Hnoi2010]Bus 公交线路 - 状压DP+矩阵快速幂