目录
- A - Game with Integers
- B - 250 Thousand Tons of TNT
- C - Yarik and Array
- D - Yarik and Musical Notes
- E - Queue Sort
A - Game with Integers
原题链接
题目描述
给定一个整数N
,A
和B
都可以对这个整数进行加一或者减一操作,从A
开始,如果A
可以让N
被3
整除,那么A
获胜,如果10
步之内A
没有获胜,那么B
获胜。
思路:思维
- 如果
N
是3
的倍数,那么A
永远无法获胜,否则A
对N
进行加一或者减一则必胜。
public static void solve() throws IOException{int n = readInt();if (n % 3 == 0) {printWriter.println("Second");} else {printWriter.println("First");}
}
B - 250 Thousand Tons of TNT
原题链接
题目描述
有N
个箱子从左到右排成一排,第i
个箱子重 a i a_i ai 吨。现在你可以使用K
辆卡车,从左到右依次将箱子装入卡车,但是每辆卡车上装入的箱子数量必须一致,但是你想让这K
辆卡车的其中两辆卡车所装货物重量之差尽可能大,求出这个最大差值。
思路:前缀和+枚举
- 先枚举每辆卡车所装箱子的数量:只需要枚举数量为 1 ≤ i ≤ n 2 1 \leq i \leq \frac{n}{2} 1≤i≤2n 的箱子,因为数量大于 n 2 \frac{n}{2} 2n后方案肯定不可行,数量为 n n n时结果肯定为 0 0 0。
- 再枚举每辆卡车所装箱子的重量之和,求出最大差值。
public static void solve() throws IOException{int n = readInt();int[] arr = new int[n + 1];for (int i = 1; i <= n; i++) {arr[i] = readInt();}long[] pre = new long[n + 1];for (int i = 1; i <= n; i++) {pre[i] = pre[i - 1] + arr[i];}long res = 0;for (int i = 1; i <= n / 2; i++) { // 枚举每辆卡车上的箱子数量if (n % i == 0) {long curMax = Long.MIN_VALUE, curMin = Long.MAX_VALUE;for (int j = i; j <= n; j += i) { // 枚举每辆卡车上的箱子重量之和curMax = Math.max(pre[j] - pre[j - i], curMax);curMin = Math.min(pre[j] - pre[j - i], curMin);}res = Math.max(curMax - curMin, res);}}printWriter.println(res);
}
C - Yarik and Array
原题链接
题目描述
有一个长度为n
的数组a
,你需要找出一个子数组,且其中的元素都是奇偶相邻的,并且这个子数组的和最大,请求出这个最大和。
思路:动态规划
- dp数组的定义为:以第
i
个元素结尾所能构成的最大子数组的和。
public static void solve() throws IOException{int n = readInt();int[] arr = new int[n + 1];for (int i = 1; i <= n; i++) arr[i] = readInt();int[] dp = new int[n + 1];dp[1] = arr[1];for (int i = 2; i <= n; i++) {// 奇偶性不同,在取前面的元素和不取前面元素中得最大值if ((arr[i - 1] & 1) != (arr[i] & 1)) {dp[i] = Math.max(arr[i], dp[i - 1] + arr[i]);} else {// 奇偶性相同,那么以第 i个元素结尾所能构成的最大子数组的和只能是arr[i]本身dp[i] = arr[i];}}int max = Integer.MIN_VALUE;for (int i = 1; i <= n; i++) {max = Math.max(max, dp[i]);}printWriter.println(max);
}
D - Yarik and Musical Notes
原题链接
题目描述
有一个长度为n
的数组a
和数组b
,数组b
的每个元素为 2 a i 2^{a_i} 2ai,你需要找出总共有多少对 b i b j = b j b i ( i ≤ j ) b_i^{b_j} = b_j^{b_i}(i \leq j) bibj=bjbi(i≤j)。
思路:组合数学
- 原式为 2 a i 2 a j = 2 a j 2 a i 2^{a_i^{2^{a_j}}} = 2^{a_j^{2^{a_i}}} 2ai2aj=2aj2ai得 a i ∗ 2 a j = a j ∗ 2 a i a_i * 2^{a_j} = a_j * 2^{a_i} ai∗2aj=aj∗2ai,再得 a i a j = 2 a j − a i \frac{a_i}{a_j} = 2^{a_j - a_i} ajai=2aj−ai,那么 ① a i = a j a_i = a_j ai=aj ② a i = 1 , a j = 2 a_i=1,a_j=2 ai=1,aj=2 ③ a i = 2 , a j = 1 a_i=2,a_j=1 ai=2,aj=1,最后进行组合计数即可。
public static void solve() throws IOException{int n = readInt();Map<Integer, Long> map = new HashMap<>();for (int i = 1; i <= n; i++) {int a = readInt();map.put(a, map.getOrDefault(a, 0l) + 1);}long res = 0;for (Long val : map.values()) {res += val * (val - 1) / 2;// 情况一}// 情况二和三res += (map.getOrDefault(1, 0l) * map.getOrDefault(2, 0l));printWriter.println(res);
}
E - Queue Sort
原题链接
题目描述
给定一个长度为n
的数组a
,你需要将其变为不递减数组。你可以进行以下操作多次:将第一个元素移至数组末尾,再将这个元素与其前面的元素对比,直至该元素严格大于他前面的元素或者成为第一个元素。如果无法将该数组变为不递减数组,输出-1
,否则输出将其变为不递减数组的最少操作数。
思路:观察
- 观察可得,如果数组中最小的元素后面出现了降序的情况,那么永远无法将数组变为不递减数组,否则输出最小的元素前面有多少个比它大的元素。
public static void solve() throws IOException{int n = readInt();int min = Integer.MAX_VALUE; // 数组中的最小元素int[] arr = new int[n];for (int i = 0; i < n; i++) {arr[i] = readInt();min = Math.min(min, arr[i]);}int idx = 0;// 数组中的最小元素第一次出现的位置for (int i = 0; i < n; i++) {if (arr[i] == min) {idx = i;break;}}boolean f = true;// 最小元素后面是否不递减for (int i = idx + 1; i < n; i++) {if (arr[i] < arr[i - 1]) {// 出现降序f = false;break;}}if (!f) {printWriter.println(-1);} else {int cnt = 0; // 最小的元素前面有多少个比它大的元素for (int i = 0; i < n; i++) {if (arr[i] > min) {cnt++;} else {break;}}printWriter.println(cnt);}
}