洛谷P2233 【HNOI2002】公交车路线

题目背景

在长沙城新建的环城公路上一共有8个公交站,分别为A、B、C、D、E、F、G、H。公共汽车只能够在相邻的两个公交站之间运行,因此你从某一个公交站到另外一个公交站往往要换几次车,例如从公交站A到公交站D,你就至少需要换3次车。(这张爆丑的图是本蒟蒻自己画的XD)


Tiger的方向感极其糟糕,我们知道从公交站A到公交E只需要换4次车就可以到达,可是tiger却总共换了n次车,注意tiger一旦到达公交站E,他不会愚蠢到再去换车。现在希望你计算一下tiger有多少种可能的乘车方案。

题目描述

输入输出格式

输入格式:

输入文件当中仅有一个正整数n(4<=n<=10000000),表示tiger从公交车站A到公交车站E共换了n次车。

输出格式:

输出文件仅有一个正整数,由于方案数很大,请输出方案数除以 1000后的余数。

----------------------------------------------------qwq的题解分割线-------------------------------------------------------

这道题看起来像是一道数学题(或许也有数学解法),但是再仔细想想也可以想到它的DP解法。先从最简单的DP开始,我们设F[ i ] [ j ]表示走 i 步到第 j 个点的方案数,不难看出F[ i ] [ j ]=F[ i-1 ] [ j-1 ]+F[ i-1 ] [ j+1 ],也就是走 i-1 步到 j 节点两侧的节点的方案数之和。于是转移也就推出来了,初始化令 F[1][2]=F[1][8]=1,即从A走一步到B和H的方案数均为1,然后递推就好。

但是这样还做不了,因为n可以到1e7,如果开一个有一维是1e7的数组肯定会MLE。我们再观察一下我们的转移方程,会发现对于每组F[ i ],它的大小只与上一步也就是F[ i-1 ]有关,所以这道题可以用滚动数组优化,滚过之后第一维只需要开到2就行,完美的解决了MLE问题。

其实到这里这道题应该就可以A掉了,但是它还可以再优化。我们可以看出来这道题有对称性,也就是走x步到B的方案数和H相同,C和G相同,D和F相同。所以我们只需要记录AE连线一侧的方案数,最后输出的时候乘以二即可,这样可以节省一半的时间和空间。

还有一些具体的转移细节在代码的注释里。

下面贴上本蒟蒻丑陋的代码

#include<iostream>
#include<cstdio>
using namespace std;
const int mod=1000;
int n,f[2][5];
int main()
{
	scanf("%d",&n);
	f[1][1]=1;//初始化 
	for(int i=2;i<=n;i++)
	{
		int k=i%2;
		f[k][1]=2*f[k^1][2]%mod;//点A的方案数来自B和H,只需要其中一个乘2就好 
		f[k][2]=(f[k^1][1]+f[k^1][3])%mod;//点B的方案数来自A和C 
		f[k][3]=(f[k^1][2]+f[k^1][4])%mod;//点C的方案数来自B和D 
		f[k][4]=f[k^1][3];//点D的方案数来自C,因为走到E之后就不会再走了,所以没有来自E的状态转移过来 
	}
	printf("%d\n",2*f[n%2][4]%mod);//答案就是到D的方案数乘2 
	return 0;
}

PS:这道题似乎可以矩阵乘法加速,但是我太菜了没搞出来qwq


猜你喜欢

转载自blog.csdn.net/kdlkswb/article/details/80515648
今日推荐