格子刷油漆 (递推)

题目大意:一个2*X的格子矩阵,请问有多少种刷油漆的方案?每次只能刷一个格子,刷完一个格子,然后只能刷它左右或者斜对角线上的格子。

题目分析:要求的是刷漆顺序的总数。

A C E G I K N P
B D F H J M O Q

假设我们有以上的格子矩阵,我们可以有以下几种刷漆方案:

一. 1.先刷第一列,然后刷第二列,再刷第三列…… 对应到表中,也就是先刷A,B两格,再刷C,D两格……如果用a[i]表示从一个端点(假设是A)开始的前i列的方法数,那么在这种情况下,a[i] = a[i-1]*2,因为每次要判断先刷上面那格,还是下面那格。所以a[1] = 1(默认从A开始刷), 当i>1时,a[i] = a[i-1]*2.

2.先刷A,然后刷C,然后回过头刷B,再刷D,然后就是从第三列的某个开始刷。 这种情况下就是:a[i] = a[i-2] * 4. 为什么是乘以4,可能是A->C->B->D->(E或F),也可能是A->D->B->C->(E或F). 难道不可以是ACDB嘛,这个真没有,如果有的话,刷完B,还怎么有间隔地刷E或F呢

3.先刷A,再刷C,再刷E,再刷G……也就是每列选取一个格子这样刷,这种情况:b[i] = b[i-1]*2,每列有两种情况,b[1]=1. 分析:可能在中途某个点返回去刷吗?不可能,因为一旦返回,无法刷另一边了。

综合1.2.3.三点,得到a[i] = (2*a[i-1]+4*a[i-2]+b[i]) * 4,因为可以从A,B,P,Q四个点出发,所以要乘以4.

二.分析完起始点是四个端点的情况,再来分析端点是中间列的某个点,假设是从第i列的上下某个点出发,前面的i-1列,方法数自然是2*b[i-1]+2*a[n-i],因为我选第i-1列开始刷时,也有两种选择,选上还是选下。同样的,后面的N-i列,方法数是2*b[n-i]*2*a[i-1],因为第i列也有上下两种选择,所以此种情况方法数:2*(2*b[i-1]*2*a[N-i]+2*a[i-1]*2*b[N-i])

综合一二两种情况,即可。注意,中间结果要取模,而且数值类型要取long long,不然在取模之前就已经超出范围了,怎么办。


代码展示:

#include <iostream>
using namespace std;

#define max 1000000007

int main(){
    int N;
    cin>>N;
    long long a[1001],b[1001];
    long long sum = 0;
    b[1] = 1;
    for(int i=2;i<=N;i++){
        b[i] = (b[i-1] * 2) % max;
    }
    a[1] = 1;
    a[2] = 6;
    for(int i=3;i<=N;i++){
        a[i] = (2*a[i-1]%max+4*a[i-2]%max+b[i]%max)%max;
    }
    sum = 4*a[N]%max;
    for(int i=2;i<N;i++){
        sum = (sum + 8*a[N-i]*b[i-1]%max+8*a[i-1]*b[N-i]%max)%max;
    }
    cout<<sum<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jaster_wisdom/article/details/79718062