51nod CSPJ 模拟题 B人行横道

赛题-人行横道 (51nod.com)

  1. 1.0 秒
  2. 262,144.0 KB
  3. 100 分

题目描述

一条有 n 条线的人行横道,这 n 条线是交错的,即一条黑线一条白线。

Noder要过马路,他不能一步完全跨过马路,途中至少要有一次踩在一条线上。他希望自己每走一步踩过的线,也是黑白交替的(单独一条白线或黑线,也算黑白交替),问他有多少种不同的走法。

由于数量太多,只需要输出对 1e9+7 取模的结果。

输入

第一行包含一个整数n(1 ≤ n ≤ 10^6),对应人行横道的长度。

输出

输出可行的方案数对 1e9+7 取模的结果。

数据范围

对于40%的数据, 1 ≤ n ≤ 20 1≤n≤20 1n20

对于60%的数据, 1 ≤ n ≤ 1000 1≤n≤1000 1n1000

对于100%的数据, 1 ≤ n ≤ 1 0 6 1≤n≤10^6 1n106

输入样例

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(n1)f(n2)1 = f(n)f(n1)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 n2 f(2)f(1)1 = f(n)f(n1)1

简单来我们可以讲变换矩阵 a, 将其变换矩阵 M = a n − 2 M = a^{n-2} M=an2,然后根据上面的计算出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=an2Fn=MF2

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值