有趣的数
题目给出三个重要条件:
- 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
- 所有的0都出现在所有的1之前,而所有的2都出现在所有的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();
}
}