当前位置:   article > 正文

Codeforces Round 912 (Div. 2) --- D1题和D2题 -- 题解_maximum and queries

maximum and queries

目录

Maximum And Queries

题目大意:

思路:

D1:

D2:

D1代码:

D2代码:


 

Maximum And Queries

Problem - D1 - Codeforces

Problem - D2 - Codeforces

题目大意:

现在给你n个数,然后你可以进行q次查询,每一次查询你都可以进行k次操作,操作的定义为选择任意一个数字让其加一,在进行小于等于k次操作后,这n个数字能得到最大的与和是多少。

D1 :数据范围 n<=10^6, q<=10^6, n*q<=10^6,a<=10^6

D2:  数据范围  n<=10^6 q<=10^6,a<=10^6

思路:

D1:

因为n*q是小于等于10^6,所以我们可以不用在意查询代价,因为一次计算代价就是 60,所以时间复杂度最高为O(6*10^7)是可以接受的。

然后计算答案应该从二进制的高位开始计算,因为如果从低位开始计算,下一次计算的时候我们这一位填1会影响计算k的大小,但是如果从高位开始计算,如果这一位需要通过操作让其变为1,那么他的低位就会变为0,并且这样的变化并不会影响低位操作次数的统计。

D2:

这里的n*q最大为10^12,这里我们在意查询代价了,所以我们应该做到查询代价为O(1)。

k最大为10^18,约等于2^60,并且2^20大于10^6(所以2^20以上的与和只能通过操作得到,所以可以直接快速求),那么我可以把2^20作为n的临界值,如果k能将ai全部提升至2^20以上,那么就直接让他全部变为最大值

否则通过预处理ai,这里用到SOSDP(可以自行了解)

  1. // dpSum[i][j] 表示i的超集,从0到j位的值的和
  2. long[][] dpSum = new long[1 << 20][20];
  3. // dpCnt[i] 表示 i的超集有多少个
  4. long[] dpCnt = new long[1 << 20];
  5. for (int i = 0; i < n; i++) {
  6. arr[i] = input.nextLong();
  7. total += arr[i];
  8. s += (t - arr[i]);
  9. dpCnt[(int) arr[i]]++;
  10. int sum = 0;
  11. for (int j = 0; j < 20; j++) {
  12. sum += (arr[i] & (1 << j));
  13. dpSum[(int) arr[i]][j] += sum;
  14. }
  15. }
  16. // 预处理dpCnt
  17. for (int i = 0; i < 20; i++) {
  18. for (int j = 0; j < 1 << 20; j++) {
  19. if ((j & (1 << i)) == 0)
  20. dpCnt[j] += dpCnt[j | (1 << i)];
  21. }
  22. }
  23. //预处理 dpSum
  24. for (int i = 0; i < 20; i++) {
  25. for (int j = 0; j < 1 << 20; j++) {
  26. for (int k = 0; k < 20; k++) {
  27. if ((j & (1 << i)) == 0)
  28. dpSum[j][k] += dpSum[j | (1 << i)][k];
  29. }
  30. }
  31. }
  32. for (int i = 0; i < q; i++) {
  33. long k = input.nextLong();
  34. long ans = 0;
  35. if (k >= s) { // 如果能直接提升到2^20及以上则直接计算。
  36. ans = t + (k - s) / n;
  37. out.println(ans);
  38. continue;
  39. }
  40. for (int j = 19; j >= 0; j--) {
  41. // dpCnt[i] 表示i的超集的个数, 如果当前答案是 110000,目标答案是 110010
  42. // dpCnt[110010]已经有这个110010二进制的数,不需要进行操作,
  43. // 所以目标答案需要进行(n - dpCnt[(int) (ans | (1 << j))]) * (1L << j),
  44. // 这里假设除了110010的超集剩余的数字从0位到第j位都为0,但是他可能不为0
  45. // 所以需要减去[ans , ans | (1 << j)] 这个范围之间的数字他的贡献
  46. long x = (n - dpCnt[(int) (ans | (1 << j))]) * (1L << j);
  47. x -= dpSum[(int) ans][j] - dpSum[(int) (ans | (1<<j))][j];
  48. if (x <= k){
  49. k -= x;
  50. ans |= (1L << j);
  51. }
  52. }
  53. out.println(ans);
  54. }

D1代码:

  1. import java.util.Scanner;
  2. /**
  3. * @ProjectName: study3
  4. * @FileName: Ex35
  5. * @author:HWJ
  6. * @Data: 2023/12/2 11:37
  7. */
  8. public class Ex35 {
  9. public static void main(String[] args) {
  10. Scanner input = new Scanner(System.in);
  11. int n = input.nextInt();
  12. int q = input.nextInt();
  13. long[] arr = new long[n];
  14. for (int i = 0; i < n; i++) {
  15. arr[i] = input.nextInt();
  16. }
  17. for (int i = 0; i < q; i++) {
  18. long k = input.nextLong();
  19. long ans = 0;
  20. long[] a = new long[n];
  21. for (int j = 0; j < n; j++) {
  22. a[j] = arr[j];
  23. }
  24. for (int j = 62; j >= 0; j--) {
  25. long sum = 0;
  26. long num = 1L << j;
  27. for (int l = 0; l < n; l++) {
  28. if ((ans & a[l]) != ans){
  29. a[l] = ans;
  30. }
  31. if ((a[l] & num) == num) continue;
  32. sum += num - (a[l] & (num - 1));
  33. if (sum > k) break;
  34. }
  35. if (sum > k) continue;
  36. k -= sum;
  37. ans += num;
  38. }
  39. System.out.println(ans);
  40. }
  41. }
  42. }

D2代码:

  1. import java.io.*;
  2. import java.math.BigInteger;
  3. import java.util.StringTokenizer;
  4. /**
  5. * @ProjectName: study3
  6. * @FileName: Ex36
  7. * @author:HWJ
  8. * @Data: 2023/12/2 11:37
  9. */
  10. public class Ex36 {
  11. public static void main(String[] args) throws IOException {
  12. int n = input.nextInt();
  13. int q = input.nextInt();
  14. long[] arr = new long[n];
  15. long s = 0;
  16. long t = 1L << 20;
  17. long total = 0;
  18. long[][] dpSum = new long[1 << 20][20];
  19. long[] dpCnt = new long[1 << 20];
  20. for (int i = 0; i < n; i++) {
  21. arr[i] = input.nextLong();
  22. total += arr[i];
  23. s += (t - arr[i]);
  24. dpCnt[(int) arr[i]]++;
  25. int sum = 0;
  26. for (int j = 0; j < 20; j++) {
  27. sum += (arr[i] & (1 << j));
  28. dpSum[(int) arr[i]][j] += sum;
  29. }
  30. }
  31. for (int i = 0; i < 20; i++) {
  32. for (int j = 0; j < 1 << 20; j++) {
  33. if ((j & (1 << i)) == 0)
  34. dpCnt[j] += dpCnt[j | (1 << i)];
  35. }
  36. }
  37. for (int i = 0; i < 20; i++) {
  38. for (int j = 0; j < 1 << 20; j++) {
  39. for (int k = 0; k < 20; k++) {
  40. if ((j & (1 << i)) == 0)
  41. dpSum[j][k] += dpSum[j | (1 << i)][k];
  42. }
  43. }
  44. }
  45. for (int i = 0; i < q; i++) {
  46. long k = input.nextLong();
  47. long ans = 0;
  48. if (k >= s) {
  49. ans = t + (k - s) / n;
  50. out.println(ans);
  51. continue;
  52. }
  53. for (int j = 19; j >= 0; j--) {
  54. // dpCnt[i] 表示i的超集的个数, 如果当前答案是 110000,目标答案是 110010
  55. // dpCnt[110010]已经有这个110010二进制的数,不需要进行操作,
  56. // 所以目标答案需要进行(n - dpCnt[(int) (ans | (1 << j))]) * (1L << j),
  57. // 这里假设除了110010的超集剩余的数字从0位到第j位都为0,但是他可能不为0
  58. // 所以需要减去[ans , ans | (1 << j)] 这个范围之间的数字他的贡献
  59. long x = (n - dpCnt[(int) (ans | (1 << j))]) * (1L << j);
  60. x -= dpSum[(int) ans][j] - dpSum[(int) (ans | (1<<j))][j];
  61. if (x <= k){
  62. k -= x;
  63. ans |= (1L << j);
  64. }
  65. }
  66. out.println(ans);
  67. }
  68. out.flush();
  69. out.close();
  70. br.close();
  71. }
  72. static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
  73. static Input input = new Input(System.in);
  74. static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  75. static class Input {
  76. public BufferedReader reader;
  77. public StringTokenizer tokenizer;
  78. public Input(InputStream stream) {
  79. reader = new BufferedReader(new InputStreamReader(stream), 32768);
  80. tokenizer = null;
  81. }
  82. public String next() {
  83. while (tokenizer == null || !tokenizer.hasMoreTokens()) {
  84. try {
  85. tokenizer = new StringTokenizer(reader.readLine());
  86. } catch (IOException e) {
  87. throw new RuntimeException(e);
  88. }
  89. }
  90. return tokenizer.nextToken();
  91. }
  92. public String nextLine() {
  93. String str = null;
  94. try {
  95. str = reader.readLine();
  96. } catch (IOException e) {
  97. // TODO 自动生成的 catch 块
  98. e.printStackTrace();
  99. }
  100. return str;
  101. }
  102. public int nextInt() {
  103. return Integer.parseInt(next());
  104. }
  105. public long nextLong() {
  106. return Long.parseLong(next());
  107. }
  108. public Double nextDouble() {
  109. return Double.parseDouble(next());
  110. }
  111. public BigInteger nextBigInteger() {
  112. return new BigInteger(next());
  113. }
  114. }
  115. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/55175
推荐阅读
相关标签
  

闽ICP备14008679号