A - Sorting with Twos
题目描述
给你一个长度为 n n n 的数组 a a a,在每次操作中,你可以选择一个非负整数 m m m ( 2 m ≤ n 2^m \leq n 2m≤n),然后让所有的 a i a_i ai ( 1 ≤ i ≤ 2 m 1 \le i \leq 2^m 1≤i≤2m)都减去 1 1 1,问是否可以通过一定次数使得数组 a a a 变成非递减数组。
思路:思维+暴力修改
- 由于 n n n很小,我们每次从坐标 1 1 1开始,往后暴力修改每一个长度为 2 m 2^m 2m的区间,这样一定可以让前面的更小,如果这样修改都无法满足,那么为
No
。
public static void solve() throws IOException{
int n = readInt();
int[] arr = utils.nextIntArray(n);
int m = 0;
boolean f = true;
int k = 10;
while (k-- > 0) {
// 如果在修改区间时,已经遇到arr[i - 1] > arr[i],那么肯定无法满足题意
// 因为该区间已经不可再分,即无法将arr[i - 1]变为更小的值
for (int i = 1; i <= Math.pow(2, m) && i <= n; i++) {
if (arr[i - 1] > arr[i]) {
f = false;
break;
}
}
if (!f) break;
// 暴力将前面都修改为最小值
for (int i = 1; i <= Math.pow(2, m) && i <= n; i++) {
arr[i] = 0;
}
m++;// 增加区间长度
}
printWriter.println(f ? "YES" : "NO");
}
B - Deja Vu
题目描述
给你一个长度为 n n n 的正整数数组 a a a 和一个长度为 q q q 的正整数数组 x x x,一共有 q q q 次修改,对于每次修改,如果 a j ( 1 ≤ j ≤ n ) a_j(1 \leq j \leq n) aj(1≤j≤n)可以被 2 x i ( 1 ≤ i ≤ q ) 2^{x_i}(1 \leq i \leq q) 2xi(1≤i≤q)整除,那么就把 2 x i − 1 2^{x_i-1} 2xi−1 加到 a j a_j aj 上。求在完成 q q q 次修改后的 a a a 数组。
思路:思维+观察
- 如果 a j a_j aj 可以被 2 x i 2^{x_i} 2xi整除,那么当 a j a_j aj加上 2 x i − 1 2^{x_{i-1}} 2xi−1后, a j a_j aj之后可以整除的 2 x k 2^{x_k} 2xk 一定小于 2 x i 2^{x_i} 2xi,即 k < i k \lt i k<i,比如 32 32 32 可以整除 2 5 2^5 25 ( i = 5 ) (i = 5) (i=5),那么 32 32 32 加上 2 4 ( i − 1 = 4 ) 2^4(i-1 = 4) 24(i−1=4)后变为 48 48 48 ,而 48 48 48 只能整除 2 p ( p < 5 ) 2^p(p \lt 5) 2p(p<5)。
- 所以对于每一个 a j a_j aj,当他可以整除 x i x_i xi时,求出 x i x_i xi在 x x x数组中的严格下降子序列即可。但是 x i x_i xi的严格下降子序列我们应该预处理好。
public static void solve() throws IOException{
int n = readInt(), q = readInt();
int[] a = utils.nextIntArray(n);
int[] x = utils.nextIntArray(q);
List<Integer>[] lists = new List[40];
Arrays.setAll(lists, g -> new ArrayList<>());
for (int i = 1; i <= 30; i++) {
lists[i].add(40);// xi最大为30,这里我们添加一个更大的值,保证降序
}
// 求出 xi的严格下降序列
for (int i = 1; i <= 30; i++) {
for (int j = 1; j <= q; j++) {
if (x[j] < lists[i].get(lists[i].size() - 1)) {//比上一次的小就添加
lists[i].add(x[j]);
}
}
}
int[] have= new int[40];// xi是否出现过
for (int i = 1; i <= q; i++) {
if (have[x[i]] == 0) {
have[x[i]] = i;
}
}
for (int i = 1; i <= n; i++) {
// 求出 ai的因数可以有多少个 2
int k = 0, t = a[i];
while (t % 2 == 0 && t != 0) {
k++;
t /= 2;
}
// 求出最近的能被 ai整除的 x数组的数 x^k
while (k >= 1 && have[k] == 0) {
k--;
}
// 根据 x^k的严格下降序列,求出最终的 ai
List<Integer> ps = lists[k];
for (Integer p : ps) {
if (a[i] % Math.pow(2, p) == 0) {
a[i] += Math.pow(2, (p - 1));
}
}
}
for (int i = 1; i <= n; i++) {
printWriter.print(a[i] + " ");
}
printWriter.println();
}