【题目】
题目描述:
Tom 者表也,数学者景也,表动则景随矣。
Tom 不喜欢数学,可数学却待 Tom 如初恋,Tom 睡觉的时候也不放过。
Tom 的梦境中出现了一个平面直角坐标系,自原点,向四方无限延伸。
Tom 在坐标系的原点,他可以向上、向左或者向右走。他可以走
n
n
n 步,但不能经过相同的点。
Tom 想知道他有多少种走法
输入格式:
输入文件仅第一行一个正整数 n n n,表示 Tom 可以走的步数。
输出格式:
输出文件共一行,输出一个正整数,表示答案(对 1 0 9 + 7 10^9+7 109+7 取模)。
样例数据:
输入
2
输出
7
备注:
【输入输出样例 1 说明】
从
(
0
,
0
)
(0,0)
(0,0) 出发走
2
2
2 步,共
7
7
7 种走法:
(0,0)->(0,1)->(0,2)
(0,0)->(0,1)->(1,1)
(0,0)->(0,1)->(-1,1)
(0,0)->(1,0)->(2,0)
(0,0)->(1,0)->(1,1)
(0,0)->(-1,0)->(-2,0)
(0,0)->(-1,0)->(-1,1)
【数据范围】
测试点编号 | n n n |
---|---|
1 1 1 ~ 2 2 2 | n < = 10 n<=10 n<=10 |
3 3 3 ~ 4 4 4 | n < = 100 n<=100 n<=100 |
5 5 5 ~ 6 6 6 | n < = 1000 n<=1000 n<=1000 |
7 7 7 ~ 8 8 8 | n < = 1 0 6 n<=10^6 n<=106 |
9 9 9 ~ 10 10 10 | n < = 1 0 9 n<=10^9 n<=109 |
【分析】
直接上题解吧,就不说暴力分了
考虑合法路径的特点,如果第 i − 1 i-1 i−1 步向上走,那么第 i i i 步可以向上、左、右走;如果第 i − 1 i-1 i−1 步向左走,那么第 i i i 步可以向上或者向左走;如果第 i − 1 i-1 i−1 步向右走,那么第 i i i 步可以向上或者向右走。
我们用 f [ i ] [ 0 ] f[i][0] f[i][0] 表示走了 i i i 步,第 i i i 步向上走的方案数; f [ i ] [ 1 ] f[i][1] f[i][1] 表示走了 i i i 步,第 i i i 步向左走的方案数; f [ i ] [ 2 ] f[i][2] f[i][2] 表示走了 i i i 步,第 i i i 步向右走的方案数,递推方程:
f
[
i
]
[
0
]
=
f
[
i
−
1
]
[
0
]
+
f
[
i
−
1
]
[
1
]
+
f
[
i
−
1
]
[
2
]
f[i][0]=f[i-1][0]+f[i-1][1]+f[i-1][2]
f[i][0]=f[i−1][0]+f[i−1][1]+f[i−1][2];
f
[
i
]
[
1
]
=
f
[
i
−
1
]
[
0
]
+
f
[
i
−
1
]
[
1
]
f[i][1]=f[i-1][0]+f[i-1][1]
f[i][1]=f[i−1][0]+f[i−1][1];
f
[
i
]
[
2
]
=
f
[
i
−
1
]
[
0
]
+
f
[
i
−
1
]
[
2
]
f[i][2]=f[i-1][0]+f[i-1][2]
f[i][2]=f[i−1][0]+f[i−1][2];
又因为 f [ i ] = f [ i ] [ 0 ] + f [ i ] [ 1 ] + f [ i ] [ 2 ] f[i]=f[i][0]+f[i][1]+f[i][2] f[i]=f[i][0]+f[i][1]+f[i][2],继续化简可以得到 f [ i ] = 2 ∗ f [ i − 1 ] + f [ i − 2 ] f[i]=2*f[i-1]+f[i-2] f[i]=2∗f[i−1]+f[i−2]
但是 n n n 最大有 1 0 9 10^9 109,直接 O ( n ) (n) (n) 递推还是不行,我们还要用到矩阵快速幂来优化,这样就降成了 O ( l o g    n ) (log \; n) (logn),就可以 A 了
这道题的关键点:找递推式以及用矩阵快速幂来优化递推
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10
#define mod 1000000007
using namespace std;
struct matrix
{
int m[N][N];
matrix(int t=0)
{
memset(m,0,sizeof(m));
for(int i=1;i<=2;++i) m[i][i]=t;
}
friend matrix operator * (const matrix &a,const matrix &b)
{
int i,j,k;
matrix c(0);
for(i=1;i<=2;++i)
for(j=1;j<=2;++j)
for(k=1;k<=2;++k)
c.m[i][j]=(c.m[i][j]+1ll*a.m[i][k]*b.m[k][j]%mod)%mod;
return c;
}
friend matrix operator ^ (matrix a,int b)
{
matrix c(1);
for(;b;b>>=1,a=a*a)
if(b&1)
c=c*a;
return c;
}
}A,B;
void init()
{
A.m[1][1]=7;A.m[1][2]=3;
A.m[2][1]=0;A.m[2][2]=0;
B.m[1][1]=2;B.m[1][2]=1;
B.m[2][1]=1;B.m[2][2]=0;
}
int main()
{
// freopen("coordinate.in","r",stdin);
// freopen("coordinate.out","w",stdout);
int n;
scanf("%d",&n);
init();
if(n==1) {printf("3");return 0;}
if(n==2) {printf("7");return 0;}
matrix C=A*(B^(n-2));
printf("%d",C.m[1][1]);
// fclose(stdin);
// fclose(stdout);
return 0;
}