【Luogu P6033】Combined fruit enhanced version

Merged Fruit Enhanced Edition

Title link: luogu P6033

General idea

There are a bunch of things. Each time you can choose two things, and at the cost of their size and sum, combine them to get one thing with their size and sum. Then combine them into one thing at the least cost.

Same as normal, but the data becomes larger, O(nlogn) cannot pass.

Ideas

The assumption here is already common.
——>No point me<——

First of all, we see that the data is large, and an O(n) algorithm is used.

Then we consider not to use heap, but to use some other methods to improve.
Greedy still use the previous greed.

The question becomes how to maintain the smallest two numbers in a pile of numbers all the time.

Then we consider using a method to sort the original sequence, where the data can be sorted by buckets, and if the data is large, it can also be sorted by radix.

Then we make another queue and record the newly generated numbers.
It is obvious that the newly generated numbers must be from small to large.
Then we choose the lower two of the first two numbers in the two queues (that is, the four numbers) each time, and then pop up, insert a new value in the queue, and record the cost.

Then do it like this.

To open long long, this is obvious.
It's obvious to start fast reading. (Then I was wrong for a long time because I didn't open it, so I made a queue version with my own)

Code

Manual queue version

#include<queue>
#include<cstdio>
#define ll long long

using namespace std;

int n;
ll ans, x, y, xx, yy, box[100001];
ll q[10000001], p[10000001], t, tt;

int read() {
    
    
	int re = 0;
	char c = getchar();
	
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') {
    
    
		re = re * 10 + c - '0';
		c = getchar();
	}
	
	return re;
}

int main() {
    
    
	n = read();
	for (int i = 1; i <= n; i++) {
    
    
		x = 1ll * read();
		box[x]++;
	}
	
	for (int i = 1; i <= 100000; i++)
		for (int j = 1; j <= box[i]; j++) {
    
    
			q[++q[0]] = i;
		}
	
	while (p[0] + q[0] - t - tt > 1) {
    
    
		x = q[t + 1];
		xx = q[t + 2];
		y = p[tt + 1];
		yy = p[tt + 2];
		
		if (xx < y && t + 2 <= q[0] || (tt + 1 > p[0])) y = xx, t += 2;
			else if (yy < x && tt + 2 <= p[0] || (t + 1 > q[0])) x = yy, tt += 2;
				else t++, tt++;
		
		ans += x + y;
		p[++p[0]] = x + y;
		if (p[0] + q[0] - t - tt <= 1) {
    
    
			break;
		}
	}
	
	printf("%lld", ans);
	
	return 0;
}

Comes with queue version

#include<queue>
#include<cstdio>
#define ll long long

using namespace std;

int n;
ll ans, x, y, xx, yy, box[200001];
queue <ll> q, p;

int read() {
    
    
	int re = 0;
	char c = getchar();
	
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') {
    
    
		re = re * 10 + c - '0';
		c = getchar();
	}
	
	return re;
}

int main() {
    
    
	n = read();
	for (int i = 1; i <= n; i++) {
    
    
		x = 1ll * read();
		box[x]++;
	}
	
	for (int i = 1; i <= 200000; i++)
		for (int j = 1; j <= box[i]; j++) {
    
    
			q.push(i);
		}
	
	while (1) {
    
    
		x = 0;
		y = 0;
		if (q.empty() && p.empty()) break;
		if (!q.empty()) xx = q.front();
			else {
    
    
				x = p.front();
				p.pop();
				if (!p.empty()) {
    
    
					y = p.front();
					p.pop();
				}
				else break;
			}
		if (!y) {
    
    
			if (!p.empty()) yy = p.front();
				else {
    
    
					x = q.front();
					q.pop();
					if (!q.empty()) {
    
    
						y = q.front();
						q.pop();
					}
					else break;
				}
		}
		if (!y) {
    
    
			if (xx < yy) x = xx, q.pop();
				else x = yy, p.pop();
			if (q.empty() && p.empty()) break;
			if (q.empty()) y = p.front(), p.pop();
				else if (p.empty()) y = q.front(), q.pop();
					else {
    
    
						xx = p.front();
						yy = q.front();
						if (xx < yy) y = xx, p.pop();
							else y = yy, q.pop();
					}
		}
		ans += x + y;
		p.push(x + y);
	}
	
	printf("%lld", ans);
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/114679255
Recommended