zoukankan      html  css  js  c++  java
  • CCF 201312-4 有趣的数

    问题描述

      我们把一个数称为有趣的,当且仅当:
      1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
      2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
      3. 最高位数字不为0。
      因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
      请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。

    输入格式

      输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。

    输出格式

      输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。

    样例输入

    4

    样例输出

    3

    题解


    dp:对一个n位数的解都基于前一个n-1位的数的最优解。

    我们对一个数的第n位规定一个状态集:即到这一位为止还有几个数字没有使用(我们有0123共四个数)。

    对第n位而言,经过归纳,有六种状态:

    状态 已用 剩余
    0 2 0 1 3
    1 2 0 1 3
    2 2 3 0 1
    3 2 0 1 3
    4 2 0 3 1
    5 2 0 1 3  

    接着,我们需要分析,每个状态可以通过哪些状态转移得到:

    状态0:只有一种可能,即状态0本身;

    状态1:①第n-1位是状态0的情况下,第n位填0(以下略写);②状态1填2或0(2与0之间并无冲突,故在第n-1位已达到状态1的情况下,在第n位填2或0都是合法的,由于有两种可能,所以需要将在状态1情况下的第n-1位的可能数乘以2);

    状态2:①状态0填3;②状态2填3(由于2与3有冲突,且3必须出现在2的后面,所以在2、3已经出现的情况下,只能在第n位填3,否则违反了规则);

    状态3:①状态1填1;②状态3填2或1,故乘以2;

    状态4:①状态1填3;②状态2填0;③状态4填0或3,故乘以2;

    状态5:①状态3填3;②状态4填1;③状态5填1或3,故乘以2;

     

    赘述:

    1.只包含数字0、1、2和3

    2.0、1、2和3各自至少出现一次

    3.所有的0都出现在1之前

    4.所有的2都出现在3之前

    5.最高位数字不为0

    数(字符串)可以分为以下六种情况(或称为状态):

    1.只包含数字2,记为S1

    2.只包含数字2和0(0开始的数0个,以此数为前缀的数均不是以0开始),记为S2

    3.只包含数字2和3,记为S3

    4.只包含数字2、0和1,并且满足所有0在1之前,记为S4

    5.只包含数字2、0和3并且满足所有2在3之前,记为S5

    6.包含任意数字(包含0、1、2和3)满足所有0在1之前,满足所有2在3之前,记为S6

    考虑递推式:

    1.对于S1,考虑其长度l,定义f(l,S1)为长度l的S1数的数量,则f(l,S1)=1。也就是说长度为l的只包含2的数只有1个。

    2.对于S2考虑其长度l,定义f(l,S2)为长度l的S2数的数量,当l=1则那么f(l,S2)=0,即f(1,S2)=0,当l>1则f(l,S2)=f(l-1,S2)*2+f(l-1,S1)。这是因为,长度为l的S2数可以是由长度为l-1的S2的数加上2或0构成,例20为长度为2的S2数,那么202和200为长度为3的S2数;另外,长度为l的S2数可以是由长度为l-1的S1的数加上0构成,例如22为长度为2S1数,那么220为长度为3的S2数。

    3.对于S3考虑其长度l,定义f(l,S3)为长度l的S3数的数量,当l=1则那么f(l,S3)=0,即那么f(1,S3)=0,当l>1则f(l,S3)=f(l-1,S3)*2+f(l-1,S1)。这是因为,长度为l的S3数可以是由长度为l-1的S3的数加上2或3构成,例23为长度为2的S3数,那么232和233为长度为3的S3数;另外,长度为l的S3数可以是由长度为l-1的S1的数加上3构成,例如22为长度为2S1数,那么223为长度为3的S3数。

    4.对于S4考虑其长度l,定义f(l,S4)为长度l的S4数的数量,当l=1则那么f(l,S4)=0,即f(1,S4)=0,当l>1则f(l,S4)=f(l-1,S4)*2+f(l-1,S2)+f(l-1,S3)。这是因为,长度为l的S4数可以是由长度为l-1的S4的数加上2或1构成(满足所有0在1之前,不可以加上0),例201为长度为3的S4数,那么2012和2011为长度为4的S4数;另外,长度为l的S4数可以是由长度为l-1的S2的数加上1构成,例如20为长度为2S2数,那么201为长度为3的S4

    同理,对于S5S6,可以得到相应的递推公式。详细参见以下的源程序。

    #include<iostream>
    using namespace std;
    const int N=1005,mod=1e9+7;
    int n;long long f[N][6];
    /**6种状态
          * 0--剩013
          * 1--剩13
          * 2--剩01
          * 3--剩3
          * 4--剩1   出现什么数能满足当前的状态,维持当前的状态。
          * 5--无    其实0 1 2 3 4这5种状态都是不满足题意的都是为了
          计算出第5种状态长度为n的时候的长度。
         **/
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            f[i][0]=1;//只放2那么肯定只有一种,也就是i个2.
            f[i][1]=(f[i-1][0]+f[i-1][1]*2)%mod;//状态1可由状态0,在i位放0得到;可由自身状态1,在i位放1或3得到
            f[i][2]=(f[i-1][0]+f[i-1][2])%mod;//状态2可由状态0放3得到;可由自身状态放0或1得到
            f[i][3]=(f[i-1][1]+f[i-1][3]*2)%mod;//状态3可由状态1,在i位放1得到,也可由自身,放2或者放1.
            f[i][4]=(f[i-1][1]+f[i-1][2]+f[i-1][4]*2)%mod;//状态4可由状态2,在i位放0得到;可由状态1放3得到,也可由自己放3或者0得到。
            f[i][5]=(f[i-1][3]+f[i-1][4]+f[i-1][5]*2)%mod;//状态5可由状态3,在i位放3得到;可由状态4在i位放1得到;可由状态5在i位放1,3得到。
        }
        cout<<f[n][5];
        return 0;
    }
  • 相关阅读:
    lower_bound和upper_bound
    memcache教程
    php header() 函数
    修复TortoiseGit文件夹和文件图标不显示
    mysql数据类型
    PDO类PDO、PDOStatement、PDOException
    mysqli和pdo对mysql数据库的操作
    php 关键字
    几个入口文件定义函数
    php --魔术常量 /魔术方法
  • 原文地址:https://www.cnblogs.com/shenben/p/12270275.html
Copyright © 2011-2022 走看看