201312-4有趣的数

思想解释参考自CSDN博客,写的比较乱我整理了一下。

首位即为左边第一位,从左到右位数依次递加。

应用动态规划的思想,核心公式为:

F[m][0]=F[m-1][0]=...=F[1][0]=1

F[m][1]=F[m-1][0]+F[m-1][1]×2

F[m][3]=F[m-1][1]+F[m-1][3]×2

F[m][4]=F[m-1][1]+F[m-1][2]+F[m-1][4]×2

F[m][5]=F[m-1][3]+F[m-1][4]+F[m-1][5]×2

初试条件为:

F[0][0] = 0

F[0][1] = 0

F[0][2] = 0

F[0][3] = 0

F[0][4] = 0

F[0][5] = 0

解释如下:

一共有如下6种状态:

状态0123
0   
1  
2  
3 
4 
5

√表示状态n包含对应的数字

状态转移效果图如下


F[m][n]的表示,第m位添加一位数字转移到状态n,到达当前状态的数字个数。

注意状态5为题设中的要求状态,即0123四个数字都存在,状态01234均是到达状态5的中间步骤

状态0~5中的数字表示进行至当前状态,形成的数字中只含有状态中包含的数字

状态0:数字首位只能放置2(0不能放在首位;首位放置1,3后面就不能放置0或2了,最终达不到0123都有的状态)

    在该状态可在后一位添加2,数字位数+1,状态不变,公式化表示即

    F[m][0]=F[m-1][0]=...=F[1][0]=1

状态1:状态1有两种形成方式

    (1)由状态0向后添加0转移得到

    (2)由状态1在末尾添加0或2转移到自身(两种途径因此乘2):前面没有1,3所以后面随便摆放0,2

    公式化表示为:

    F[m][1]=F[m-1][0]+F[m-1][1]×2

状态2:有两种形成方式

    (1)状态0后加3转移得到

    (2)自身末尾加3转移得到:前面放几个2可以在状态0循环获得,末尾不能加2了,因为2必须在3前面

    公式化表示为:

    F[m][2]=F[m-1][0]+F[m-1][2]×2

状态3:有两种形成方式

    (1)状态2填1转移得到

    (2)状态3本身末尾添加1或2转移到自身,因为前方有1所以后面不能放0了

    公式化表示为:

    F[m][3]=F[m-1][1]+F[m-1][3]×2

状态4:有三种形成方式

    (1)状态1填3转移得到

    (2)状态2填0转移得到

    (3)状态4末尾添加0或3,因为前方有3所以后面不能放2

    公式化表示为:

    F[m][4]=F[m-1][1]+F[m-1][2]+F[m-1][4]×2

状态5:有三种形成方式

    (1)状态3填3转移得到

    (2)状态4填1转移得到

    (3)状态5末尾添加1或3,因为前方有1,3所以后面不能放0,2

    公式化表示为:

    F[m][5]=F[m-1][3]+F[m-1][4]+F[m-1][5]×2


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const long long MOD = 1000000007;
const int MAX_N = 1001;

int main(){
    int n;//输入数字的位数
    long long data[MAX_N][6];
    cin>>n;
    memset(data,0,sizeof(data));
    for(int i = 1; i <= n; i++){
        data[i][0] = 1;
        data[i][1] = (data[i-1][0] + data[i-1][1]*2)%MOD;
        data[i][2] = (data[i-1][0] + data[i-1][2])%MOD;
        data[i][3] = (data[i-1][1] + data[i-1][3]*2)%MOD;
        data[i][4] = (data[i-1][1] + data[i-1][2] + data[i-1][4]*2)%MOD;
        data[i][5] = (data[i-1][3] + data[i-1][4] + data[i-1][5]*2)%MOD;
    }
    cout<<data[n][5]<<endl;
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值