目录
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);
}
}