第十四届蓝桥杯三月真题刷题训练——第 7 天

三角回文数

原题链接

三角回文数

问题描述

todo:这里复制题目描述

输入及输出格式

填空题直接输出答案即可

参考样例

填空题直接输出答案即可

解题思路

根据题目描述,数 x 为三角回文数需要满足两个条件:

  1. x 是一个回文数
  2. 存在一个正整数 k ,使得 1 ~ k 的累加和等于 x

所以只需要实现这两个条件的 check 函数即可

  • 对于条件 1 ,可以使用双指针来进行判断
  • 对于条件 2 ,可以使用二分来进行判断

    因为 k 肯定是小于等于 x 的,所以我们可以在 1 ~ x 的范围内进行二分。设二分的值为 mid ,如果[1, mid]的累加和大于等于 x ,那么答案的范围一定在[1, mid]中,否则答案的范围在(mid, x]中。

参考代码

import java.util.*;
import java.io.*;
public class Main {
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	
	/**
	  *  判断回文数
	 */
	public static boolean check1(long x) {
		char[] ch = Long.toString(x).toCharArray();
		int l = 0, r = ch.length - 1;
		while (l < r) {
			if (ch[l] != ch[r]) return false;
			l++;
			r--;
		}
		return true;
	}
	
	/**
	  *  判断三角数
	 */
	public static boolean check2(long x) {
		long l = 1, r = x;
		while (l < r) {
			long mid = l + ((r - l) >> 1);
			if (mid * (mid + 1) / 2 >= x) {
				r = mid;
			} else {
				l = mid + 1;
			}
		}
		return l * (l + 1) / 2 == x;
	}
	
	public static void main(String[] args) throws Exception {
		
		for (long i = 20220514; ; i++) {
			if (check1(i) && check2(i)) {
				out.println(i);
				break;
			}
		}
        
		out.flush();
		in.close();
	}

}

数数

原题链接

数数

问题描述

todo:这里复制题目描述

输入及输出格式

填空题直接输出答案即可

参考样例

填空题直接输出答案即可

解题思路

考察分解质因数

参考代码

import java.util.*;
import java.io.*;
public class Main {
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	
    /**
      * 判断质因子个数是否等于12
      */
	public static boolean check(int x) {
		int p = 2, cnt = 0;
		while (p * p <= x) {
			while (x % p == 0) {
				x /= p;
				cnt++;
			}
			p++;
		}
		if (x > 1) cnt++;
		return cnt == 12;
	}

	public static void main(String[] args) throws Exception {
		
//		int cnt = 0;
//		for (int i = 2333333; i <= 23333333; i++) {
//			if (check(i)) cnt++;
//		}
//		
//		out.println(cnt);
		
		out.println(25606);
		out.flush();
		in.close();
	}

}

数组切分

原题链接

数组切分

问题描述

todo:这里复制题目描述

输入及输出格式

参考样例

todo:这里是参考样例

数据范围及运行限制

在这里插入图片描述

解题思路

根据 子数组 / 切分方案数 / 数字很大需要对 1e9 + 7 取模 这些关键字基本可以推断出这是一道动态规划问题了。
题目给定一个长度为 n 的数组,并且数组元素恰好是一个 1 ~ n 的排列,这是一个很重要的条件!!!
思考区间[i, j]是一段连续的自然数需要满足什么条件呢?

假设 x1, x2 , x3, … xn 是一段连续的自然数,并且已经有序,即 x1 < x2 < x3 < … < xn
不能得出这段区间的元素个数为 xn - x1 + 1
得出结论:如果区间[i, j]的长度等于这个区间最大值 - 最小值 + 1,那么这个区间一定是一段连续的自然数
对于某一个区间,只需要定义两个变量来维护最大值最小值即可,不需要对区间进行排序。

状态定义
定义 f[i] 为将前 i 个数划分成若干满足条件的区间的方案数,f[n] 即为答案
状态转移
假设[j, i]是一段连续的自然数,那么[j, i]就可以和前面的所有满足条件的区间进行匹配
当满足条件时 f[i] = f[i] + f[j - 1]
初始化
当某一个区间元素数量为 1 时,这个区间一定是满足条件的,每个单独的数显然是 (长度为 1 的) 一段连续的自然数。
f[1] = f[1] + f[0] = 1 -> f[0] = 1

参考代码

import java.util.*;
import java.io.*;
public class Main {
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	
	static final int MOD = (int)1e9 + 7;
	static int N = (int)1e4 + 10, n;
	static int[] a = new int[N], f = new int[N];
	
	public static void main(String[] args) throws Exception {
		n = Integer.parseInt(in.readLine());
		String[] s = in.readLine().split(" ");
		for (int i = 1; i <= n; i++) a[i] = Integer.parseInt(s[i - 1]);
		
		f[0] = 1;
		for (int i = 1; i <= n; i++) {
			// mx:区间最大值  mn:区间最小值
			int mx = a[i], mn = a[i];
			for (int j = i; j >= 1; j--) {
				mx = Math.max(mx, a[j]);
				mn = Math.min(mn, a[j]);
				// i - j + 1 为区间长度
				if (i - j + 1 == mx - mn + 1) {
					f[i] = (f[i] + f[j - 1]) % MOD;
				}
			}
		}
		out.println(f[n]);

		out.flush();
		in.close();
	}

}

倍数问题

原题链接

倍数问题

问题描述

todo:这里复制题目描述

输入及输出格式

todo:这里是输入输出格式

参考样例

todo:这里是参考样例

运行限制

1s

解题思路

分情况进行分析,假设最终找到的三个数为 a、b、c

  1. a、b、c 都是 k 的倍数
  2. a、b、c 中有两个数是 k 的倍数,不难得出第三个数必须也是 k 的倍数,可以跟第一条归为一条
  3. a、b、c 中有一个数是 k 的倍数,那么其他两个数的和必须是 k 的倍数,即(x % k) + (y % k) = k
  4. a、b、c 都不是 k 的倍数,那么必须满足 (a % k) + (b % k) + (c % k) == k

因此我们只需要统计出 0 ~ k - 1这个范围中每个余数最大的三个数即可

为什么是三个数?
假设数组元素为[14, 20, 26, 32, 38] k = 6 ,不难发现每个数和 k 取余都是相同的,14、20满足条件的时候32、38 肯定也是满足条件的,而且还能保证最终的累加和更大。

参考代码

import java.util.*;
import java.io.*;
public class Main {
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	
	static int N = (int)1e5 + 10, K = (int)1e3 + 10, n, k;
	static int[] a = new int[N];
	// 存放每个数 % k 的三个最大值,其中 m[i][2] >= m[i][1] >= m[i][0]
	static int[][] m = new int[K][3];
	
	public static void check(int x) {
		int mod = x % k;
		// 如果 x 比最大值还要大,就整体全部替换
		// 比如:x = 100  k = 10  三个最大值为[10, 20, 30]
		// 如果 x 比第二个值大,之前的第二个值变成最小值,再将 x 换成第二个值
		// 如果 x 比第一个值大,直接更换即可
		if (x >= m[mod][2]) {
			m[mod][0] = m[mod][1];
			m[mod][1] = m[mod][2];
			m[mod][2] = x;
		} else if (x >= m[mod][1]) {
			m[mod][0] = m[mod][1];
			m[mod][1] = x;
		} else if (x > m[mod][0]) {
			m[mod][0] = x;
		}
	}
	
	public static void main(String[] args) throws Exception {
		// input
		String[] nk = in.readLine().split(" ");
		n = Integer.parseInt(nk[0]);
		k = Integer.parseInt(nk[1]);
		String[] s = in.readLine().split(" ");
		for (int i = 0; i < n; i++) {
			a[i] = Integer.parseInt(s[i]);
			// 输入的时候进行判断
			check(a[i]);
		}
		int ans = 0;
		// 枚举余数
		for (int i = 0; i < k; i++) {
			// 最大的一个数都是 0 ,说明不存在这个余数(数组中不存在一个数 % k = i)
			if (m[i][2] == 0) continue;
			// a b c 为满足条件的三个数
			int a = m[i][2], b = 0, c = 0;
			for (int j = i; j < k; j++) {
				// c_mod为第三个数的余数
				// 比如:k = 5,i = 1,j = 2  这时 c_mod = k - i - j
				// 还有一种情况:k = 10,i = 8,j = 9 这时 c_mod = k - i - j 就是负数了
				// 为了防止负数的产生,我们先 + k 再 % k 就可以了
				int c_mod = (k + k - i - j) % k;
				if (j == i) {
					if (m[i][1] == 0) continue;
					b = m[i][1];
					if (c_mod == i) {
						if (m[i][0] == 0) continue;
						c = m[i][0];
					}
				} else {
					if (m[j][2] == 0) continue;
					b = m[j][2];
					if (c_mod == i) {
						if (m[i][1] == 0) continue;
						c = m[i][1];
					} else if (c_mod == j) {
						if (m[j][1] == 0) continue;
						c = m[j][1];
					} else {
						if (m[c_mod][2] == 0) continue;
						c = m[c_mod][2];
					}
				}	
				ans = Math.max(ans, a + b + c);
			}
		}
		out.println(ans);

		out.flush();
		in.close();
	}

}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值