文章目录
三角回文数
原题链接
问题描述
输入及输出格式
填空题直接输出答案即可
参考样例
填空题直接输出答案即可
解题思路
根据题目描述,数 x 为三角回文数
需要满足两个条件:
- x 是一个回文数
- 存在一个正整数 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();
}
}
数数
原题链接
问题描述
输入及输出格式
填空题直接输出答案即可
参考样例
填空题直接输出答案即可
解题思路
考察分解质因数
参考代码
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();
}
}
数组切分
原题链接
问题描述
输入及输出格式
参考样例
数据范围及运行限制
解题思路
根据 子数组 / 切分方案数 / 数字很大需要对 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();
}
}
倍数问题
原题链接
问题描述
输入及输出格式
参考样例
运行限制
1s
解题思路
分情况进行分析,假设最终找到的三个数为 a、b、c
- a、b、c 都是 k 的倍数
- a、b、c 中有两个数是 k 的倍数,不难得出第三个数必须也是 k 的倍数,可以跟第一条归为一条
- a、b、c 中有一个数是 k 的倍数,那么其他两个数的和必须是 k 的倍数,即
(x % k) + (y % k) = k
- 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();
}
}