zoukankan      html  css  js  c++  java
  • 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后的余数。

    输入输出样例

    输入样例#1: 
    6
    输出样例#1: 
    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 ightarrow E$和$D ightarrow E$都是单向转移的。

      这样显然时空都会炸,空间还好解决,转移时直接滚掉第2维。

      时间上我们发现可以去掉$E$点改为统计$F,D$的方案数,而方案数是对称的,于是只需要统计一边的4个点的方案就好了。

      这样去直接dp是可以过的。

      但是还可以优化,根据优化后的4个点的dp转移构造矩阵

        初始矩阵:$[1,0,0,0]$,中间矩阵:$egin{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
    ",2*ans.a[0][3]%mod);
    }
    
    int main(){
        cin>>n;
        solve(n-1);
        return 0;
    }
  • 相关阅读:
    linux 命令——19 find (转)
    linux 命令——18 locate (转)
    linux 命令——17 whereis(转)
    linux 命令——16 which(转)
    linux 命令——15 tail (转)
    linux 命令——14 head (转)
    Java for LeetCode 038 Count and Say
    Java for LeetCode 037 Sudoku Solver
    Java for LeetCode 036 Valid Sudoku
    Java for LeetCode 035 Search Insert Position
  • 原文地址:https://www.cnblogs.com/five20/p/9632982.html
Copyright © 2011-2022 走看看