Blue Bridge Cup Log Hero Problem Solution

Title: Master Log


    atm participated in the quick calculation training class. After hard training, he could quickly calculate the logarithm with base 2. He was called Hero Log.


    One day, Hero Log's friend drd has some integer sequences that need to be transformed, and Hero Log just casts mana...


    The rule of transformation is: Each integer of a certain subsequence becomes: [log_2 (x) + 1] where [] means round down,
that is, take the base 2 logarithm of each number, and then round it down.
    For example, after one operation on the sequence 3 4 2, the sequence becomes 2 3 2.
    
    drd needs to know what the sum of the sequence is after each such operation.


[Input format]
Two positive integers nm in the first line.
The second line contains n numbers, representing a sequence of integers, all positive numbers.
Next m lines, two numbers LR in each line indicate that atm is operating in the interval [L, R] this time, and the sequence number starts from 1.


[Output format]
Output m lines, which in turn represent the sum of the entire sequence after each operation performed by the atm.


For example, input:
3 3
5 6 4
1 2
2 3
1 3 The


program should output:
10
8
6




[Data Range]
For 30% of the data, n, m <= 10^3
For 100% of the data, n, m < = 10^5




resource convention:
Peak memory consumption < 256M
CPU consumption < 1000ms




Please output strictly as required, do not superfluous and print redundant content like: "Please enter...".


All code is placed in the same source file, after debugging, copy and submit the source code.


Note: The main function needs to return 0
Note: Only use the ANSI C/ANSI C++ standard, do not call special functions that depend on the compilation environment or operating system.
Note: All dependent functions must be explicitly #include <xxx> in the source file, and common header files cannot be omitted through project settings.


When submitting, take care to select the desired compiler type.



Many problem solutions on the Internet are to solve the problem of the first 30% of the data. As for all the data, after asking other big guys for advice, I tried to write it down,

It's also been an example, I don't know if it's right or not.


      思路呢,主要就是会发现一个大于1的正数(这题应该是默认输入数据在Integer范围内的吧),经过5次操作之后,
都会变成一个常数2,以后无论在进行多少次操作都维持在2上不变。至于值为1的正数,无论进行多少次变换操作,
值始终为1。
     所以,我们可以用f数组预处理,f[i][j]表示第i个数变换了j次后的结果,则f[i][0]=arr[i](第i个数),
f[i][j]=[log_2 (f[i][j-1]) + 1]。然后看这个数据范围,应该也是对区间整体操作,直接用add数组表示直接对区间整体变换的次数。然后这道对add数组更新,有点类似线段树中的简单更新操作。查询整个序列的和,则可以加个参数addnum,表示之前该区间所属区间已经整体变换的次数。然后对这个区间实际总体最少变换次数=大区间最少变换次数+当前区间直接最少变换次数(例如,10个数,[1,3]区间add值为2,[1,5]区间add值为1,[1,10]区间add值为1,则[1,3]至少变了2+1+1=4次)。然后呢,如果整体区间最少变换次数值>=5,则区间中元素和为2*区间长度-区间中数值为1的数的
个数。否则,就递归下去到单个元素,根据其变换次数,利用预处理的f数组处理,更新ans。


    可能还是比较难理解,结合代码相对会好些,代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Random;
import java.util.StringTokenizer;

class Reader {
	static BufferedReader reader;
	static StringTokenizer tokenizer;

	static void init(InputStream input) {
		reader = new BufferedReader(new InputStreamReader(input));
		tokenizer = new StringTokenizer("");
	}

	static String next() throws IOException {
		while (!tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(reader.readLine());
		}
		return tokenizer.nextToken();
	}

	static int nextInt() throws IOException {
		return Integer.parseInt(next());
	}
}

public class Main {

	/**
	 * @param args
	 */
	static long ans;
	static int n, m, ql, qr;
	static int arr[], num1[], add[];
	static long f[][];

	private static void init() {
		f = new long[n + 1][6];
		int val;
		for (int i = 1; i <= n; i++) {
			f[i][0] = arr[i];
			for (int j = 1; j <= 5; j++) {
				val = (int) (Math.log(f[i][j - 1]) / Math.log(2)) + 1;
				f[i][j] = val;
			}
		}
	}

	private static void maintain1(int o) {
		num1[o] = num1[o * 2] + num1[o * 2 + 1];
	}

	private static void cal1(int o, int l, int r) {
		if (l == r) {
			if (arr[l] == 1)
				num1[o] = 1;
			return;
		}
		int mid = (l + r) / 2;
		cal1(o * 2, l, mid);
		cal1(o * 2, mid + 1, r);
		maintain1(o);
	}

	private static void update(int o, int l, int r) {
		if ((ql <= l) && (qr >= r)) {
			add[o]++;
			return;
		}
		int mid = (l + r) / 2;
		if (mid >= ql)
			update(o * 2, l, mid);
		if (mid + 1 <= qr)
			update(o * 2 + 1, mid + 1, r);
	}

	private static void query(int o, int l, int r, int addnum) {
		int anum = addnum + add[o];
		if (anum >= 5) {
			ans = ans + (long)((r - l + 1) * 2 - num1[o]);
			return;
		}
		if (l == r) {
			ans = ans + f[l][anum];
			return;
		}
		int mid = (l + r) / 2;
		query(o * 2, l, mid, anum);
		query(o * 2 + 1, mid + 1, r, anum);
	}

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		Reader.init(System.in);
		n = Reader.nextInt();
		m = Reader.nextInt();
		arr = new int[n + 1];
		for (int i = 1; i <= n; i++)
			arr[i] = Reader.nextInt();
		init();
		num1 = new int[4 * n + 1];
		add = new int[4 * n + 1];
		cal1(1, 1, n);
		for (int i = 1; i <= m; i++) {
			ql = Reader.nextInt();
			qr = Reader.nextInt();
			update(1, 1, n);
			ans = 0;
			query(1, 1, n, 0);
			System.out.println(ans);
		}
	}

}


Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326748371&siteId=291194637