P2233 [HNOI2002]公交车路线
题目背景
在长沙城新建的环城公路上一共有8个公交站,分别为A、B、C、D、E、F、G、H。公共汽车只能够在相邻的两个公交站之间运行,因此你从某一个公交站到另外一个公交站往往要换几次车,例如从公交站A到公交站D,你就至少需要换3次车。
Tiger的方向感极其糟糕,我们知道从公交站A到公交E只需要换4次车就可以到达,可是tiger却总共换了n次车,注意tiger一旦到达公交站E,他不会愚蠢到再去换车。现在希望你计算一下tiger有多少种可能的乘车方案。
题目描述
输入输出格式
输入格式:输入文件由bus.in读入,输入文件当中仅有一个正整数n(4<=n<=10000000),表示tiger从公交车站A到公交车站E共换了n次车。
输出格式:输出到文件bus.out。输出文件仅有一个正整数,由于方案数很大,请输出方案数除以 1000后的余数。
输入输出样例
6
8
说明
8条路线分别是:
(A→B→C→D→C→D→E),(A→B→C→B→C→D→E),
(A→B→A→B→C→D→E),(A→H→A→B→C→D→E),
(A→H→G→F→G→F→E),(A→H→G→H→G→F→E),
(A→H→A→H→G→F→E),(A→B→A→H→G→F→E)。
Solution:
本题简单矩阵加速dp。
首先,一个很显然的dp是定义状态$f[i][j]$表示到了$i$点走了$j$步的方案数,则$f[i][j]=f[i-1][j-1]+f[i+1][j-1]$,注意的是$F\rightarrow E$和$D\rightarrow E$都是单向转移的。
这样显然时空都会炸,空间还好解决,转移时直接滚掉第2维。
时间上我们发现可以去掉$E$点改为统计$F,D$的方案数,而方案数是对称的,于是只需要统计一边的4个点的方案就好了。
这样去直接dp是可以过的。
但是还可以优化,根据优化后的4个点的dp转移构造矩阵:
初始矩阵:$[1,0,0,0]$,中间矩阵:$\begin{bmatrix}
0& 1& 0& 0\\
2& 0& 1& 0\\
0& 1& 0& 1\\
0& 0& 1& 0
\end{bmatrix}$
最后答案就是$A[1,4]*2$啦。
代码:
/*Code by 520 -- 9.11*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) #define Clr(p) memset(&p,0,sizeof(p)) using namespace std; const int mod = 1e3; int n; struct matrix{int a[4][4],r,c;}; il matrix Mul(matrix x,matrix y){ matrix tp; Clr(tp); tp.r=x.r,tp.c=y.c; For(i,0,3) For(j,0,3) For(k,0,3) tp.a[i][j]=(tp.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod; return tp; } il void solve(int k){ matrix tp,ans; Clr(tp),Clr(ans); ans.r=1,ans.c=tp.r=tp.c=4; ans.a[0][0]=ans.a[1][1]=ans.a[2][2]=ans.a[3][3]=1; tp.a[1][0]=2,tp.a[0][1]=tp.a[1][2]=tp.a[2][1]=tp.a[2][3]=tp.a[3][2]=1; while(k){ if(k&1) ans=Mul(ans,tp); k>>=1; tp=Mul(tp,tp); } printf("%d\n",2*ans.a[0][3]%mod); } int main(){ cin>>n; solve(n-1); return 0; }