首页 > 编程知识 正文

蓝桥杯算法比赛题目,蓝桥杯经典算法

时间:2023-05-03 08:39:10 阅读:273140 作者:216

【问题描述】
把 n分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包
含数字 2和 4,一共有多少种不同的分解方法?
注意交换 3 个整数的顺序被视为同一种方法,例如 1999+3+18 和
1999+18+3 被视为同一种。
【输入格式】
输入一行包含一个整数 n。
【输出格式】
输出一行,包含一个整数,表示满足条件的分解方法种数。
【样例输入】
2019
【样例输出】
40785
【评测用例规模与约定】
对于所有评测用例,100 ≤ n ≤ 2500。


在遍历的时候,怎么能保证数不重复? 是本题比较难的一个点

做一个题,得有一个题的收获,这道题给我的收获是如果你无法想象出这道题的突破口在哪,去试,去看,实践出真知.

书归正传. 我们慢慢来捋.

这道题的整体思想是通过两层循环,i和j,然后通过这两个数就能得出第三个数k来.
然后我们想办法对这三个数进行筛选就可以了.

关于怎么让数不重复的原理,是这样的:

12 21 和 21 12有什么区别呢? 我们只需要保证后面的数比前面大,就不会重复了.

关键的点在于,这三个数该怎么去遍历呢?

在代码中,有这么几个点,得跟您说说是怎么来的:

在测试的时候,我让num等于100,遍历了所有的情况,来跟您讨论代码的特定实现,只有先把确定的问题找到具体实现,我们才能想,为n时的变化是什么.
1.k和j的关系是什么?k到什么时候就该停止?
我们可以看到,当i为1的时候,实际上是遍历了i为1,j从2开始,一直到98,因为i和k至少要有一个1,所以j最大为98.
但是值得注意的是,当遍历到我蓝色区域最终位置的时候,后面的内容实际上是在重复前面的结果,而我们题目说了,交换顺序算一个,也就是说,当k<=j的时候,我就该停止了.

k和j的关系我们讨论完了. 接下来


接下来我们讨论的是k的极限在哪? 不难看出,当i=1时,j最大为49.当i为2的时候,j最大为48,当i为3的时候,j最大为48,当i为4的时候,j最大为47.总之当i不断变大的时候,j一定会越来越小的.不过这个值的规律我没找出来. 这不妨碍我们找到它的极限,当i为1的时候,j为49. 而我们的num=100.意味着j的循环终止条件应该是num / 2 - 1. num=100时,最大情况为1 49 50. num=101(奇数)时,最大情况是1 49 51. 都满足这个条件.




接下来的问题是,i的极限在哪?
i < num / 3. 为什么是小于?而不是≤,又为什么是num / 3? 为什么把i的极限定为num / 3是让我最开始也很迷惑的问题.
首先k(第二个数)有一个前提,就是它肯定要比前一个数大.
i     j
1 2-99
2 3-98
3 4-97. 拿这一组来说,就应该是3 4,3 5,3 6,3 7,3 … 97. 如果你的j可以小于i,就会出现3 3(相同的抹去),3 2(3 2和i为2的时候,2 3重复了.),3 1(和i为1时,1 3重复了).
我们已经知道了j必须大于i,而且,k要大于j. k>j>i
那么i的极限是什么呢?当我们遍历到i为32的时候,发现只有一个值满足条件.

而当i为33的时候,一个满足条件的都没有了. 我们想想这是为什么呢? 当num为100的时候,我们要把num分为三个正整数,如果第一个数等于num的1/3的话,就是33,而第二个数不能比第一个数小,那么它最少也是34,而第三个数又不能比第二个数小,它最少是35. 但是这已经超过100了.

也就是说,当num为3的倍数的时候, 拿99举例,当i最大为num / 3 - 1. j最小为num / 3 .k最小为 num / 3 + 1. 即32 33 34
当num - 1为3的倍数的时候,拿100举例,当i最大为num / 3 - 1. j最小为num / 3 .k最小为 num / 3 + 2 (多加了一个1是把余数补上) 即 32 33 35.
当num - 2为3的倍数的时候,拿101举例,当i最大为num / 3 - 1. j最小为num / 3 .k最小为 num / 3 + 3 (多加了一个2是把余数补上) 即 32 33 36.
但是我们的循环实际上也不涉及到k的极限值,所以省了不少麻烦.

现在我们总结一下:

我们的目的是给我们一个整数,我们能把它分为三个互不相同的正整数,而且顺序转换的数为一种.

我们讨论了k和j之间的关系,j是变化的,k会随着j的变化而变化,我们发现当k≤j的时候,就该跳出当前的循环了.接下来我们讨论了j的最大值问题. 当i为3的倍数的时候,如99,j最大值为(num - 1) / 2. 为 1 49 50.
当i为%3余1的时候,如100,j最大值为(num - 2) / 2. 为 1 49 50.
当i为%3余2的时候,如101,j最大值为(num - 3) / 2. 为 1 49 51.
实际上是(num - 1 - (i % 3 )) / 2.接下来我们讨论了i和j之间的关系,我们发现当j>i的时候,才有意义.接下来我们讨论了i的最大值应该是什么? 我们发现i的最大值为num / 3 - 1
import java.util.Scanner;public class resolutionNumber { public static void main(String[] args) { Scanner input = new Scanner(System.in); // 输入一个数 int num = input.nextInt(); // 用来计数 int count = 0; // i从1到num / 3 - 1 我们上面已经讨论过了. for (int i = 1; i <= num / 3 - 1; i++) { // judge用来判断i是否包含2或4,如果包含,直接跳过即可. if(judge(i)) continue; // 第二个数从i + 1开始,终值我们在上面也已经讨论过了. 其实这里你干脆可以写j <= num. 因为下面如果k <= j了也会跳出. 所以这里的终止条件其实无所谓这么精确. for (int j = i + 1; j <= (num - 1 - (i % 3 )) / 2; j++) { // 得出k的值 int k = num - i - j; if(k <= j) { break; } // 如果k和j包含2或4这个数字,跳过循环. if(judge(k) || judge(j) ) continue; // 否则就是满足条件的,三个数,而且互不相等,还不包含2或4. count ++; } } } // true 为找到了 public static boolean judge(int num) { // num + ""是把数字变成字符串类型. 然后分割一下存在nums数组里. // 接下来对比每一个字符,如果是2或4,就说明找到了,return true. String[] nums = (num +"").split(""); for(String i : nums) { if (i.equals("2") || i.equals("4")) { return true; } } return false; }}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。