赛题-人行横道 (51nod.com)
- 1.0 秒
- 262,144.0 KB
- 100 分
题目描述
一条有 n 条线的人行横道,这 n 条线是交错的,即一条黑线一条白线。
Noder要过马路,他不能一步完全跨过马路,途中至少要有一次踩在一条线上。他希望自己每走一步踩过的线,也是黑白交替的(单独一条白线或黑线,也算黑白交替),问他有多少种不同的走法。
由于数量太多,只需要输出对 1e9+7 取模的结果。
输入
第一行包含一个整数n(1 ≤ n ≤ 10^6),对应人行横道的长度。
输出
输出可行的方案数对 1e9+7 取模的结果。
数据范围
对于40%的数据, 1 ≤ n ≤ 20 1≤n≤20 1≤n≤20;
对于60%的数据, 1 ≤ n ≤ 1000 1≤n≤1000 1≤n≤1000;
对于100%的数据, 1 ≤ n ≤ 1 0 6 1≤n≤10^6 1≤n≤106;
输入样例
3
输出样例
6
样例解释
设 3 条线编号为 1,2,3 ,符合条件的走法包括:(以下方案中的数字表示踩到的线)
(1)1,2,3;(2)1,2;(3)2,3;(4)1;(5)2;(6)3。
思路分析
这个题目不难看出,递推公式是: F[n] = F[n-1] + f[n-2] + 2; 如果按照这个公式,我们的时间复杂度为O(N).
//# (http://www.51nod.com/Contest/Problem.html#contestProblemId=5147)
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int f[3];
int main()
{
int n;
cin >> n;
f[1] = 1, f[2] = 3;
for(int i = 3; i <= n; i ++ )
f[i % 3] = ((f[(i - 1) % 3] % mod) + (f[(i - 2) % 3] % mod) + 2) % mod;
cout << f[n] % mod << endl;
return 0;
}
如果用矩阵快速幂时间复杂度可以达到O(Log(N)) 级别。
[
1
1
2
1
0
0
0
0
1
]
⋅
[
f
(
n
−
1
)
f
(
n
−
2
)
1
]
=
[
f
(
n
)
f
(
n
−
1
)
1
]
\begin{bmatrix} 1 & 1 & 2 \\ 1 & 0 & 0\\ 0 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} f(n-1)\\ f(n-2) \\ 1 \end{bmatrix} =\begin{bmatrix} f(n)\\ f(n-1)\\ 1 \end{bmatrix}
⎣
⎡110100201⎦
⎤⋅⎣
⎡f(n−1)f(n−2)1⎦
⎤=⎣
⎡f(n)f(n−1)1⎦
⎤
[ 1 1 2 1 0 0 0 0 1 ] n − 2 ⋅ [ f ( 2 ) f ( 1 ) 1 ] = [ f ( n ) f ( n − 1 ) 1 ] \begin{bmatrix} 1 & 1 & 2 \\ 1 & 0 & 0\\ 0 & 0 & 1 \end{bmatrix} ^{n-2} \cdot \begin{bmatrix} f(2)\\ f(1) \\ 1 \end{bmatrix} =\begin{bmatrix} f(n)\\ f(n-1)\\ 1 \end{bmatrix} ⎣ ⎡110100201⎦ ⎤n−2⋅⎣ ⎡f(2)f(1)1⎦ ⎤=⎣ ⎡f(n)f(n−1)1⎦ ⎤
简单来我们可以讲变换矩阵 a, 将其变换矩阵 M = a n − 2 M = a^{n-2} M=an−2,然后根据上面的计算出Fn。
最后答案就是
F
n
[
0
]
[
0
]
Fn[0][0]
Fn[0][0].
[
1
1
2
1
0
0
0
0
1
]
=
a
M
=
a
n
−
2
F
n
=
M
⋅
F
2
\begin{bmatrix} 1 & 1 & 2 \\ 1 & 0 & 0\\ 0 & 0 & 1 \end{bmatrix} =a\\ M = a^{n-2}\\ Fn = M\cdot F2
⎣
⎡110100201⎦
⎤=aM=an−2Fn=M⋅F2
Code
//# (http://www.51nod.com/Contest/Problem.html#contestProblemId=5147)
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
typedef long long LL;
const LL MOD = 1e9 + 7;
// 快读
inline LL read()
{
LL x = 0, f = 1;
char s = getchar();
while (s < '0' || s > '9')
{
if (s == '-')
f = -f;
s = getchar();
}
while (s >= '0' && s <= '9')
{
x = (x << 3) + (x << 1) + (s ^ 48);
s = getchar();
}
return x * f;
}
// 实现矩阵乘法;
vector<vector<LL>> mul(vector<vector<LL>> &a, vector<vector<LL>> &b, LL mod)
{
int n = a.size(); // a矩阵行数
int m = b[0].size(); // b 矩阵列数
int t = b.size(); // b 矩阵行数
vector<vector<LL>> c(n, vector<LL>(m, 0));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
for (int k = 0; k < t; k++)
{
c[i][j] = (c[i][j] + a[i][k] * b[k][j] % mod) % mod;
}
}
}
return c;
}
// 实现矩阵快速幂;
vector<vector<LL>> qmi(vector<vector<LL>> &a, LL k, LL mod)
{
vector<vector<LL>> I{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; // 单位矩阵I
while (k)
{
if (k & 1)
I = mul(I, a, mod);
a = mul(a, a, mod);
k >>= 1;
}
return I;
}
int main()
{
LL n = read();
// cout << n << endl;
if (n == 1)
{
cout << 1 << endl;
return 0;
}
// 初始化a矩阵
vector<vector<LL>> a{{1, 1, 2}, {1, 0, 0}, {0, 0, 1}};
// 把a矩阵做快速幂n-2 次方
auto M = qmi(a, n - 2, MOD);
// 初始化F2 = {f[2],f[1],1}
vector<vector<LL>> F2{{3}, {1}, {1}};
auto Fn = mul(M, F2, MOD);
cout << Fn[0][0];
return 0;
}