zoukankan      html  css  js  c++  java
  • [BZOJ 4417][Shoi2013]超级跳马

    4417: [Shoi2013]超级跳马

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 379  Solved: 230
    [Submit][Status][Discuss]

    Description

    现有一个n行m列的棋盘,一只马欲从棋盘的左上角跳到右下角。每一步它向右跳奇数列,且跳到本行或相邻行。跳越期间,马不能离开棋盘。例如,当n = 3, m = 10时,下图是一种可行的跳法。
     
    试求跳法种数mod 30011。

    Input

    仅有一行,包含两个正整数n, m,表示棋盘的规模。

    Output

    仅有一行,包含一个整数,即跳法种数mod 30011。

    Sample Input

    3 5

    Sample Output

    10

    HINT

    对于100%的数据,1 ≤ n ≤ 50,2 ≤ m ≤ 10^9

    题解

    首先我们发现由于某个点的状态可以从与它所在列的编号的奇偶性不同的所有列转移, 所以这应该是一个前缀和.

    而第 $i$ 列的前缀和可以从前一列转移, 但奇数列与偶数列所转移的位置并不同, 所以转移过程中需要记录两个参考向量. 这样的话转移过程中的向量维数就是 $2n$ , 我们就需要一个 $2n imes 2n$ 的矩阵了. 我的转移矩阵大概长这样:

    其中左上部分用于统计答案, 左下部分把奇偶性相同的列也加和起来, 右上部分用于把上一列答案下推一列.

    然后最后一轮的时候要把左下和右上部分置零(其实主要是左下部分置零, 因为奇偶性相同的列不能再加入答案了)

    A掉之后整个人都赛艇了2333333

    参考代码

    GitHub

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <iostream>
     5 #include <algorithm>
     6 
     7 const int MOD=30011;
     8 
     9 int n,m;
    10 
    11 struct Matrix{
    12     int n;
    13     int m[160][160];
    14     Matrix(int n=0){
    15         this->n=n;
    16         memset(m,0,sizeof(m));
    17     }
    18 };
    19 
    20 struct Vector{
    21     int n;
    22     int v[160];
    23     Vector(int n=0){
    24         this->n=n;
    25         memset(v,0,sizeof(v));
    26     }
    27 };
    28 
    29 Vector operator* (const Vector& v,const Matrix& m){
    30     Vector ans(v.n);
    31     for(int i=1;i<=v.n;i++)
    32         for(int j=1;j<=v.n;j++)
    33             (ans.v[j]+=1ll*v.v[i]*m.m[i][j])%=MOD;
    34     return ans;
    35 }
    36 
    37 Matrix operator* (const Matrix& a,const Matrix& b){
    38     Matrix ans(a.n);
    39     for(int i=1;i<=a.n;i++)
    40         for(int j=1;j<=a.n;j++)
    41             for(int k=1;k<=a.n;k++)
    42                 (ans.m[i][j]+=1ll*a.m[i][k]*b.m[k][j])%=MOD;
    43     return ans;
    44 }
    45 
    46 int main(){
    47     scanf("%d%d",&n,&m);
    48     Vector v(2*n);
    49     Matrix mx(2*n);
    50     v.v[1]=1;
    51     for(int i=1;i<=n;i++){
    52         mx.m[i+n][i]=1;
    53         mx.m[i][i+n]=1;
    54         for(int j=std::max(1,i-1);j<=std::min(n,i+1);j++){
    55             mx.m[i][j]=1;
    56         }
    57     }
    58     m-=2;
    59     while(m>0){
    60         if((m&1)!=0){
    61             v=v*mx;
    62         }
    63         mx=mx*mx;
    64         m>>=1;
    65     }
    66     memset(mx.m,0,sizeof(mx.m));
    67     for(int i=1;i<=n;i++){
    68         for(int j=std::max(1,i-1);j<=std::min(n,i+1);j++){
    69             mx.m[i][j]=1;
    70         }
    71     }
    72     if((m&1)==0)
    73         v=v*mx;
    74     printf("%d
    ",v.v[n]);
    75     return 0;
    76 }
    Backup

     

  • 相关阅读:
    IDA Supported Processors
    Hex-Rays Decompiler
    USB ISP(ICSP) Open Programmer < PWM ADC HV PID >
    A SCSI command code -- SIMPLIFIED DIRECT-ACCESS DEVICE (RBC)
    How to match between physical usb device and its drive letter?
    记录一下公司数据库升级的步骤
    Windows2003 SQL2005解决系统Administrator密码不知道的问题
    在SSMS里批量删除表、存储过程等各种对象
    用SQLSERVER里的bcp命令或者bulkinsert命令也可以把dat文件导入数据表
    分享一张SQLSERVER执行流程的图片
  • 原文地址:https://www.cnblogs.com/rvalue/p/7719112.html
Copyright © 2011-2022 走看看