CSP 201312-4 有趣的数 Java

题目给出三个重要条件:

  1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
  2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
  3. 最高位数字不为0。

根据这三个条件,我们可以在得出一个结论:
4.最高位数字只能是2
这是因为最高位不能是1,因为所有的0都要在1前面。同理不能是3,因此只能为2。
并且,限制只在01之间,23之间存在

统计方案一般都要按照分情况讨论,就是对各种情况进行分类。

枚举

分析

一步步分析,最高位必须是2,接下来看n-1位
在这里插入图片描述

根据题目要求,每个数字都必须出现,那么01至少出现2次,最高出现n-2次。
假设01总共占据k个数位,那么从n-1中选取,k的取值为2<=k<=n-2
在这里插入图片描述
继续探究01,在01的数位选取完毕后,再看01的排列问题,由于所有的0都必须在1的前面,所以01所占的k个数位,必定是左边为0,右边为1的形态
在这里插入图片描述
设0的个数为t,那么1的个数为k-t
由于01至少出现一次,那么t的取值为1<=t<=k-1,因此01的排列情况为k-1种
同理,23的排列情况为n-k-1种
因此,当一个k值确定的情况下,有以下这么多的答案
在这里插入图片描述

而k值的范围,在前面已经分析出来,因此本题的答案就是

for (int k = 2; k <= n - 2; k++) {
    
    
	//C[n - 1][k]表示n-1个数位中取出k个位数的方法数
	res += (k - 1) * (n - k - 1) * C[n - 1][k];
}

由于数据量比较大,记得在相关的地方取余。

解题代码

import java.util.*;

public class Main{
    
    
    public static void main(String[] args) {
    
    
        Scanner input = new Scanner(System.in);
        
        int n = input.nextInt();
        int MOD = (int)(1e9 + 7);
        int[][] C = new int[n][n];
        //这里是求组合数的一个小算法
        for (int i = 0; i < n; i ++) {
    
    
            for (int j = 0; j <= i; j ++) {
    
    
               if (j == 0) {
    
    
                   C[i][j] = 1;
               } else {
    
    
                   C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
               }
            }
        }
        
        //此处为了方便我直接使用了长整型
        long res = 0;
        for (long k = 2; k <= n - 2; k ++) {
    
    
            res = (res + (k - 1) * (n - k - 1) * C[n - 1][(int)k]) % MOD;
        }
        
        System.out.println(res);
        
        input.close();
    }
}

状态转换 --> 动态规划

分析每个数位可能存在的状态,既然如此,那么每个状态都要满足题目的要求
那么,从最高位到最低位开始分析,应该有以下状态:


 - 只用了2, 没有用0,1,3
 - 只用了2、0,没有用1,3
 - 只用了2、3,没有用0、1
 - 只用了2、0、1,没有用3
 - 只用了2、0、3,没有用1
 - 全都用了

只有上述六种状态,至于类似用了2、1,没有用0、3,这种状态是不存在的,因为0必须在1的前面,有1肯定会有0的。

扫描二维码关注公众号,回复: 13043186 查看本文章

假设上面六种状态标记位状态0到状态5
假设i作为从高位到低位的第i个数字,可推导出状态关系:

s[i][0] = 1

s[i][1] = s[i - 1][0] + s[i - 1][1] * 2

s[i][2] = s[i - 1][0] + s[i - 1][2]

s[i][3] = s[i - 1][1] + s[i - 1][3] * 2

s[i][4] = s[i - 1][1] + s[i - 1][2] + s[i - 1][4] * 2

s[i][5] = s[i - 1][3] + s[i - 1][4] + s[i - 1][5] * 2

可以试着自己梳理一下,以n为6做个例子,从高位到低位,状态对应的个数为:
在这里插入图片描述
推导出关系,很容易编写代码

解题代码

import java.util.*;

public class Main{
    
    
    public static void main(String[] args) {
    
    
        Scanner input = new Scanner(System.in);
        
        int MOD = (int)(1e9 + 7);
        int n = input.nextInt();
        long[][] s = new long[n + 1][6];
        
        //此处我并没有详细处理是否溢出的问题
        for (int i = 1; i <= n; i++) {
    
    
            s[i][0] = 1;
            s[i][1] = (s[i - 1][0] + s[i - 1][1] * 2) % MOD;
            s[i][2] = (s[i - 1][0] + s[i - 1][2]) % MOD;
            s[i][3] = (s[i - 1][1] + s[i - 1][3] * 2) % MOD;
            s[i][4] = (s[i - 1][1] + s[i - 1][2] + s[i - 1][4] * 2) % MOD;
            s[i][5] = (s[i - 1][3] + s[i - 1][4] + s[i - 1][5] * 2) % MOD;
        }
        
        System.out.println(s[n][5]);
        
        input.close();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43349112/article/details/113963802