CF 611 E. New Year Parties


输入 n(<=2e5) 和长为 n 的数组 a(1<=a[i]<=n)。
对于每个 a[i],你可以将其 +1 或 -1,每个 a[i]至多修改一次。
输出修改后的 a 的不同元素个数的最小值和最大值。
不同元素个数即 len(set(a))。

思路:
最大值 : 排序 + 贪心
能减就减,不能减的话,能保持尽量保持,不能保持,就加一
最小值:计数 + 贪心
考虑上一个使用的位置,能和就和,不能和就加一(向上靠拢)

  1. static final int N = 200010;
  2. static int[] a = new int[N], b = new int[N];
  3. static int n;
  4. static void solve() {
  5. n = ni();
  6. for (int i = 0; i < n; i++) {
  7. a[i] = ni();
  8. b[a[i]]++;
  9. }
  10. Arrays.sort(a, 0, n);
  11. int max = 0;
  12. Set<Integer> set = new HashSet<>();
  13. for (int i = 0; i < n; i++) {
  14. if (!set.contains(a[i] - 1))
  15. set.add(a[i] - 1);
  16. else if (!set.contains(a[i]))
  17. set.add(a[i]);
  18. else
  19. set.add(a[i] + 1);
  20. }
  21. max = set.size();
  22. int min = 0, pre = -1;
  23. for (int i = 1; i <= n; i++) {
  24. if (b[i] == 0) continue;
  25. if (pre == i - 1 || pre == i) {
  26. continue;
  27. } else {
  28. min++;
  29. pre = i + 1;
  30. }
  31. }
  32. out.println(min + " " + max);
  33. }

CF 802 F. Puzzle

给定2行n列的01原数组,以及2行n列的目标数组,问将原数组通过交换相邻位置元素,最少需要多少步能变至目标数组,若无合法方案,输出-1

输入:
第一行表示n
第2,3行为各有n 个用空格分隔的数字,表示原数组
第4,5行为各有n 个用空格分隔的数字,表示目标数组

输出
最小步数,若没有,输出-1

思路:
将原数组中的1按是否在目标集合中分为两类,第一种是变换前已经在目标位置中,第二种是在变换前不在目标位置中。
先考虑1维的情况
如果某个1已经在目标集和中,说明不用对其进行操作,代价为0
如果某个1不在目标集和中,说明需要将其移动至目标集和中,代价移动步数
具体做法:将在集和中的已经有数字的位置记为0,没有数字的记为-1,将在集和外的数字对应位置记为1
从前往后,计算前缀和,若当前前缀和x大于0,说明有x个数还未移动至目标集中,每个都还需1步,总代价res += x
若当前前缀和x小于0,说明有x个目标集中的位置缺数,总代价为res += -x

考虑二维情况
如果某一位置,两维前缀和异号,说明可将上面一个数字移动至下边的目标集,或者将下面的一个数字移动至上面的目标集中,总代价 +1.

  1. static final int N = 200010;
  2. static int[][] a = new int[2][N];
  3. static int[][] b = new int[2][N];
  4. static int n;
  5. static void solve() {
  6. n = ni();
  7. int s1 = 0, s2 = 0;
  8. for (int i = 0; i < 2; i++) {
  9. for (int j = 1; j <= n; j++) {
  10. a[i][j] = ni();
  11. s1 += a[i][j];
  12. }
  13. }
  14. for (int i = 0; i < 2; i++) {
  15. for (int j = 1; j <= n; j++) {
  16. b[i][j] = ni();
  17. s2 += b[i][j];
  18. }
  19. }
  20. if (s1 != s2) {
  21. out.println(-1);
  22. return;
  23. }
  24. for (int i = 1; i <= n; i++) {
  25. if (b[0][i] == 1) {
  26. if (a[0][i] == 1)
  27. a[0][i] = 0;
  28. else a[0][i] = -1;
  29. }
  30. if (b[1][i] == 1) {
  31. if (a[1][i] == 1)
  32. a[1][i] = 0;
  33. else a[1][i] = -1;
  34. }
  35. }
  36. long p1 = 0, p2 = 0;
  37. long res = 0;
  38. for (int i = 1; i <= n; i++) {
  39. p1 += a[0][i];
  40. p2 += a[1][i];
  41. if (p1 * p2 >= 0)
  42. res += Math.abs(p1) + Math.abs(p2);
  43. else {
  44. long x = Math.min(Math.abs(p1), Math.abs(p2));
  45. if (p1 < 0) p1 += x;
  46. else p1 -= x;
  47. if (p2 < 0) p2 += x;
  48. else p2 -= x;
  49. res++;
  50. res += Math.abs(p1) + Math.abs(p2);
  51. }
  52. }
  53. out.println(res);
  54. }

CF 605A. Sorting Railway Cars

题意描述:
给定一个长度为n的数组,不超过100000。
数组中的所有数正好是1-n的某个排列。
每次操作如下:任选一个数放在队头或队尾
问最少几次操作使数组按递增顺序排列?
输入:
第一行,一个整数n表示数组长度
第二行,空格隔开的n个整数(ai != aj && 1 <= ai,aj <= n)
思路:
一次移动一定能将一个数字放到其应在的位置
排好序后的序列和原序列相比,考虑有哪些数没有移动过!
没有动过的数中间一定不会再有别的数字
即找数值连续的最长上升子序列或排序后的下标最长递增子数组(连续)

  1. // 数值连续的最长上升子序列
  2. static int N = 100010;
  3. static int[] a = new int[N];
  4. static int[] f = new int[N];
  5. static int n;
  6. static void solve() {
  7. n = ni();
  8. for (int i = 1; i <= n; i++) a[i] = ni();
  9. int max = 0;
  10. for (int i = 1; i <= n; i++) {
  11. f[a[i]] = f[a[i] - 1] + 1;
  12. max = Math.max(max, f[a[i]]);
  13. }
  14. out.println(n - max);
  15. }
  1. // 下标最长递增子数组
  2. static int N = 100010;
  3. static int[][] a = new int[N][2];
  4. static int[] b = new int[N];
  5. static int[] f = new int[N];
  6. static int n;
  7. static void solve() {
  8. n = ni();
  9. for (int i = 1; i <= n; i++) {
  10. a[i][0] = ni();
  11. a[i][1] = i;
  12. }
  13. Arrays.sort(a, 1, n + 1, (o1, o2) -> (o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0]));
  14. int max = 0;
  15. int c = 0;
  16. for (int i = 1; i <= n; i++) {
  17. if (a[i][1] > a[i - 1][1]) {
  18. c++;
  19. } else {
  20. c = 1;
  21. }
  22. max = Math.max(max, c);
  23. }
  24. out.println(n - max);
  25. }

扩展:
如果原数组取值任意怎么办?