赞
踩
目录
现在给你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
因为n*q是小于等于10^6,所以我们可以不用在意查询代价,因为一次计算代价就是 60,所以时间复杂度最高为O(6*10^7)是可以接受的。
然后计算答案应该从二进制的高位开始计算,因为如果从低位开始计算,下一次计算的时候我们这一位填1会影响计算k的大小,但是如果从高位开始计算,如果这一位需要通过操作让其变为1,那么他的低位就会变为0,并且这样的变化并不会影响低位操作次数的统计。
这里的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(可以自行了解)
- // dpSum[i][j] 表示i的超集,从0到j位的值的和
- long[][] dpSum = new long[1 << 20][20];
- // dpCnt[i] 表示 i的超集有多少个
- long[] dpCnt = new long[1 << 20];
- for (int i = 0; i < n; i++) {
- arr[i] = input.nextLong();
- total += arr[i];
- s += (t - arr[i]);
- dpCnt[(int) arr[i]]++;
- int sum = 0;
- for (int j = 0; j < 20; j++) {
- sum += (arr[i] & (1 << j));
- dpSum[(int) arr[i]][j] += sum;
- }
- }
-
- // 预处理dpCnt
- for (int i = 0; i < 20; i++) {
- for (int j = 0; j < 1 << 20; j++) {
- if ((j & (1 << i)) == 0)
- dpCnt[j] += dpCnt[j | (1 << i)];
- }
- }
-
- //预处理 dpSum
- for (int i = 0; i < 20; i++) {
- for (int j = 0; j < 1 << 20; j++) {
- for (int k = 0; k < 20; k++) {
- if ((j & (1 << i)) == 0)
- dpSum[j][k] += dpSum[j | (1 << i)][k];
- }
- }
- }
-
- for (int i = 0; i < q; i++) {
- long k = input.nextLong();
- long ans = 0;
- if (k >= s) { // 如果能直接提升到2^20及以上则直接计算。
- ans = t + (k - s) / n;
- out.println(ans);
- continue;
- }
-
- for (int j = 19; j >= 0; j--) {
- // dpCnt[i] 表示i的超集的个数, 如果当前答案是 110000,目标答案是 110010,
- // dpCnt[110010]已经有这个110010二进制的数,不需要进行操作,
- // 所以目标答案需要进行(n - dpCnt[(int) (ans | (1 << j))]) * (1L << j),
- // 这里假设除了110010的超集剩余的数字从0位到第j位都为0,但是他可能不为0,
- // 所以需要减去[ans , ans | (1 << j)] 这个范围之间的数字他的贡献
- long x = (n - dpCnt[(int) (ans | (1 << j))]) * (1L << j);
- x -= dpSum[(int) ans][j] - dpSum[(int) (ans | (1<<j))][j];
- if (x <= k){
- k -= x;
- ans |= (1L << j);
- }
- }
- out.println(ans);
- }
- import java.util.Scanner;
-
- /**
- * @ProjectName: study3
- * @FileName: Ex35
- * @author:HWJ
- * @Data: 2023/12/2 11:37
- */
- public class Ex35 {
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
- int n = input.nextInt();
- int q = input.nextInt();
- long[] arr = new long[n];
- for (int i = 0; i < n; i++) {
- arr[i] = input.nextInt();
- }
- for (int i = 0; i < q; i++) {
- long k = input.nextLong();
- long ans = 0;
- long[] a = new long[n];
- for (int j = 0; j < n; j++) {
- a[j] = arr[j];
- }
- for (int j = 62; j >= 0; j--) {
- long sum = 0;
- long num = 1L << j;
- for (int l = 0; l < n; l++) {
- if ((ans & a[l]) != ans){
- a[l] = ans;
- }
- if ((a[l] & num) == num) continue;
- sum += num - (a[l] & (num - 1));
- if (sum > k) break;
- }
- if (sum > k) continue;
- k -= sum;
- ans += num;
- }
- System.out.println(ans);
- }
- }
- }
- import java.io.*;
- import java.math.BigInteger;
- import java.util.StringTokenizer;
-
- /**
- * @ProjectName: study3
- * @FileName: Ex36
- * @author:HWJ
- * @Data: 2023/12/2 11:37
- */
- public class Ex36 {
- public static void main(String[] args) throws IOException {
- int n = input.nextInt();
- int q = input.nextInt();
- long[] arr = new long[n];
- long s = 0;
- long t = 1L << 20;
- long total = 0;
- long[][] dpSum = new long[1 << 20][20];
- long[] dpCnt = new long[1 << 20];
- for (int i = 0; i < n; i++) {
- arr[i] = input.nextLong();
- total += arr[i];
- s += (t - arr[i]);
- dpCnt[(int) arr[i]]++;
- int sum = 0;
- for (int j = 0; j < 20; j++) {
- sum += (arr[i] & (1 << j));
- dpSum[(int) arr[i]][j] += sum;
- }
- }
-
- for (int i = 0; i < 20; i++) {
- for (int j = 0; j < 1 << 20; j++) {
- if ((j & (1 << i)) == 0)
- dpCnt[j] += dpCnt[j | (1 << i)];
- }
- }
-
- for (int i = 0; i < 20; i++) {
- for (int j = 0; j < 1 << 20; j++) {
- for (int k = 0; k < 20; k++) {
- if ((j & (1 << i)) == 0)
- dpSum[j][k] += dpSum[j | (1 << i)][k];
- }
- }
- }
-
- for (int i = 0; i < q; i++) {
- long k = input.nextLong();
- long ans = 0;
- if (k >= s) {
- ans = t + (k - s) / n;
- out.println(ans);
- continue;
- }
- for (int j = 19; j >= 0; j--) {
- // dpCnt[i] 表示i的超集的个数, 如果当前答案是 110000,目标答案是 110010,
- // dpCnt[110010]已经有这个110010二进制的数,不需要进行操作,
- // 所以目标答案需要进行(n - dpCnt[(int) (ans | (1 << j))]) * (1L << j),
- // 这里假设除了110010的超集剩余的数字从0位到第j位都为0,但是他可能不为0,
- // 所以需要减去[ans , ans | (1 << j)] 这个范围之间的数字他的贡献
- long x = (n - dpCnt[(int) (ans | (1 << j))]) * (1L << j);
- x -= dpSum[(int) ans][j] - dpSum[(int) (ans | (1<<j))][j];
- if (x <= k){
- k -= x;
- ans |= (1L << j);
- }
- }
- out.println(ans);
- }
- out.flush();
- out.close();
- br.close();
- }
- static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
- static Input input = new Input(System.in);
- static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- static class Input {
- public BufferedReader reader;
- public StringTokenizer tokenizer;
-
- public Input(InputStream stream) {
- reader = new BufferedReader(new InputStreamReader(stream), 32768);
- tokenizer = null;
- }
-
- public String next() {
- while (tokenizer == null || !tokenizer.hasMoreTokens()) {
- try {
- tokenizer = new StringTokenizer(reader.readLine());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- return tokenizer.nextToken();
- }
-
- public String nextLine() {
- String str = null;
- try {
- str = reader.readLine();
- } catch (IOException e) {
- // TODO 自动生成的 catch 块
- e.printStackTrace();
- }
- return str;
- }
-
- public int nextInt() {
- return Integer.parseInt(next());
- }
-
- public long nextLong() {
- return Long.parseLong(next());
- }
-
- public Double nextDouble() {
- return Double.parseDouble(next());
- }
-
- public BigInteger nextBigInteger() {
- return new BigInteger(next());
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。