蓝桥杯31天冲刺之九 [java]

文章目录

  • 最大乘积(模拟枚举)
  • 阶乘约数(数学)
  • 含2天数
  • K倍区间(同余定理)

最大乘积(模拟枚举)

蓝桥杯31天冲刺之九 [java]_第1张图片

题目链接:https://www.lanqiao.cn/problems/629/learning/

这个题和昨天的神奇的算式非常的相似,只是比他更难了一点,昨天总共只有两种情况,但是今天有8种情况

我的这种做法和昨天你的类似,先从begin遍历到end,并且找出其中9位数字都不同的,然后将它进行拆分计算,但是我这个放到官网运行超时了,可能是因为数字量太大了吧,不过最后直接提交答案通过了,填空题,也无所谓了。如果是大题的话我觉得可以优化一下查找的序列,可以先使用回溯法的排列树找到所有合法的序列,然后再去拆分这个序列中的每个元素,这样就少了很多判断序列是否合法的时间了,有兴趣的可以自己动手尝试一下

我这里在拆分的时候只取了前面的一半,因为如果要一直遍历到最后的话肯定是有一个对称的序列可以取到另外四组的,例如987513462 -> 98751 * 3462和346298751 -> 3462*98751,其实这里也能优化,直接取前一半的序列然后遍历完所有的组合情况,这有就可以少判断一半的序列是否合法,应该也可以优化很多

答案:839542176

package daily;

import java.util.HashSet;
import java.util.Set;

/**
 * https://www.lanqiao.cn/problems/629/learning/
 * 
 * @author Jia
 *
 */
public class day3_16_1 {
	public static void main(String[] args) {
		int begin = 123456789;
		int end = 987654322;
		int maxVal = 0;

		for (int i = begin; i < end; i++) {
			if (!judgeValid(i)) {
				continue;
			}
			for (int j = 1; j <= 4; j++) {
				// 这里分为 1 8, 2 7, 3 6, 4 5,四组,后面的组合在其他排列里可以保证出现
				int num1 = (int) (i / (Math.pow(10, 9 - j)));
				int num2 = (int) (i % (Math.pow(10, 9 - j)));
				int temp = num1 * num2;
				if (!judgeValid(temp)) {
					continue;
				}
				maxVal = Math.max(num1 * num2, maxVal);
			}
		}
		System.out.println(maxVal);
	}

	/**
	 * 判断9位是否都不相同
	 * 
	 * @param temp
	 * @return
	 */
	private static boolean judgeValid(int temp) {
		Set<Integer> set = new HashSet<>();
		while (temp > 0) {
			int num = temp % 10;
			if (num == 0 || set.contains(num)) {
				break;
			}
			set.add(num);
			temp = temp / 10;
		}
		return set.size() == 9;
	}

}

阶乘约数(数学)

蓝桥杯31天冲刺之九 [java]_第2张图片

题目链接: https://www.lanqiao.cn/problems/1020/learning/

首先,我相信很多和我一样,看完有点懵,不知道正约数是什么,附上百度百科的解释:正因数,或称为正约数,指的是一个整数中大于0的因数。如:12的正因数有1,2,3,4,6,12。因数必须是整数,所以任何整数的最小正因数都是1

这个题要用到一点数学知识,叫做唯一分解定理,呃名字是听高大上的,但我估计直接看数学推导会直接看懵了,而且这东西哪怕不知道这个定理,自己自然而然的也能推出来这东西。

这里说下我的理解:把一个数字分解为由纯质数组成的数字,例如可以将12分解成2 2 3,则可以得到12的因数总共有6个,即(2 + 1) * (1 + 1),直观一点的解释就是有两个2,一个3,我可以取,也可以不取,可以取一个2,也可以取两个2,因此最后就可以得到12的因数有1 2 3 4 6 12, 1的话可以理解成既没有取2也没有取3,也就是上面那个乘法式子最后加的1。现在解释那个式子是什么意思,简单来说,前面的数字是当前这个质数出现的次数,就是你可以取几次,后面的加1表示不取这个数,也就是说对于这一个数来说,总共存在(m + 1)种情况,要么取要么不取,然总共有n个数,最后的结果就是 ( m 1 + 1 ) ∗ ( m 2 + 1 ) ∗ . . . (m_1+1)*(m_2+1)*... (m1+1)(m2+1)...,一直到最后

答案是:39001250856960000

package daily;

import java.util.Arrays;

/**
 * https://www.lanqiao.cn/problems/1020/learning/
 * 
 * @author Jia
 *
 */
public class day3_16_2 {
	public static void main(String[] args) {
		int n = 100;
		boolean[] isPrimary = getPrimaryList(n);

		// 将所有数字分解为纯质数因数,并统计每个质数出现的次数
		int[] primaryCount = new int[n + 1];
		for (int i = 1; i <= 100; i++) {
			int temp = i;
			int j = 2;
			while (temp != 1) {
				if (isPrimary[j] && temp % j == 0) {
					// 当j为素数并且可以整除的时候 primaryCount[j] 加1
					primaryCount[j]++;
					temp /= j;
				} else {
					// 否则看下一个j
					j++;
				}
			}
		}

		// 统计结果
		long ans = 1;
		for (int i = 2; i < primaryCount.length; i++) {
			if (primaryCount[i] != 0) {
				ans *= (primaryCount[i] + 1);
			}
		}
		System.out.println(ans);
	}

	/**
	 * 得到质数列表
	 * 
	 * @param n
	 * @return
	 */
	private static boolean[] getPrimaryList(int n) {
		boolean[] isPrimary = new boolean[n + 1];// 存储质数
		Arrays.fill(isPrimary, true);
		for (int i = 2; i <= 100; i++) {
			int j = i + i;
			while (j <= 100) {
				isPrimary[j] = false;
				j += i;
			}
		}
		return isPrimary;
	}
}

含2天数

蓝桥杯31天冲刺之九 [java]_第3张图片

题目链接: https://www.lanqiao.cn/problems/1038/learning/

这个做法参考的含2天数,我的做法不知道哪里错了,结果差了一点,贴在下面了,希望大佬们可以帮我看看哪里有问题

这个做法用的是java的一个内置类LocalData,可以直接提取时间,然后就可以判断年份,月份和天是否包含2

这里记得要先判断年,这样可以利用java逻辑运算符的短路原理减少一点计算量

答案:1994240

package daily;

import java.time.LocalDate;

/**
 * https://www.lanqiao.cn/problems/1038/learning/
 * 
 * @author Jia
 *
 */
public class day3_16_3_ac {
	public static void main(String[] args) {
		LocalDate beginTime = LocalDate.of(1900, 1, 1);// 开始时间
		LocalDate endTime = LocalDate.of(9999, 12, 31);// 结束时间

		int year;
		int month;
		int day;
		long ans = 0;
		while (beginTime.compareTo(endTime) <= 0) {
			// 当还没到最后一天时进行判断
			year = beginTime.getYear();
			month = beginTime.getMonthValue();
			day = beginTime.getDayOfMonth();
			if (containsTwo(year) || containsTwo(month) || containsTwo(day)) {
				ans++;
			}
			beginTime = beginTime.plusDays(1);
		}
		System.out.println(ans);
	}

	/**
	 * 判断传入的数字中是否含有2
	 * 
	 * @param num
	 * @return
	 */
	private static boolean containsTwo(int num) {
		while (num > 0) {
			if (num % 10 == 2) {
				return true;
			}
			num /= 10;
		}
		return false;
	}
}

下面这种做法不知道哪里错了,最后的结果是1984984,与答案差了10000天左右,有点迷,希望大佬们可以帮我找一下,实在是不熟悉Calendar类

package daily;

import java.util.Calendar;

/**
 * https://www.lanqiao.cn/problems/1038/learning/
 * 
 * @author Jia
 *
 */
public class day3_16_3_wa {
	public static void main(String[] args) {
		Calendar c = Calendar.getInstance();
		c.clear();
		long ans = 0;
		for (int year = 1990; year <= 9999; year++) {
			c.clear();
			c.set(Calendar.YEAR, year);

			if (containsTwo(year)) {
				// 如果年份包含2,直接把这一年的天数加上即可
				ans += c.getActualMaximum(Calendar.DAY_OF_YEAR);
				continue;
			}
			// 遍历月
			for (int month = 0; month < 12; month++) {
				c.set(Calendar.MONTH, month);
				int maxDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
				if (containsTwo(month + 1)) {
					// 如果月份包含2,直接把这一个月的天数加上即可
					ans += maxDay + 1;
					continue;
				}

				// 遍历天
				for (int day = 1; day <= maxDay; day++) {
					if (containsTwo(day)) {
						// 把这一天加上
						ans++;
					}
				}
			}
		}
		System.out.println(ans);
	}

	/**
	 * 判断传入的数字中是否含有2
	 * 
	 * @param num
	 * @return
	 */
	private static boolean containsTwo(int num) {
		while (num > 0) {
			if (num % 10 == 2) {
				return true;
			}
			num /= 10;
		}
		return false;
	}
}

K倍区间(同余定理)

蓝桥杯31天冲刺之九 [java]_第4张图片

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2830(需登录才能看到题目)

前三个题给我整的有点麻了,第四题估计又是个dp(或者前缀和),还不太会,先鸽了,大家加油,可以参考这个K倍区间

你可能感兴趣的:(蓝桥杯,java,蓝桥杯,算法)