P4829 kry loves 2048 题解

题目传送门:P4829 kry loves 2048

此题解不开 O2 能过。


解法:

双倍经验:P6033 合并果子 加强版

类似于合并果子的解法:最优方案一定是两个最小的数据进行合并,一共会合并 \(n-1\) 次。

先根据题意造好数据,建立两个队列 \(q_1,q_2\) 来模拟合并过程。

再用桶排把每个数字出现次数统计一下。

把排好序后的数字推入队列 \(q_1\) 中,易发现 \(q_1\) 中的数是单调不降的。

再维护一个队列 \(q_2\),存储操作过后的数据,易发现 \(q_2\) 中的数也是单调不降的。

最后,操作时,只需要取出两次队列 \(q_1,q_2\) 的队头的最小值,再把操作后的数据推入 \(q_2\) 的队尾即可。

注意:操作时,有两种操作方法,即把最小的数 \(\times 2\) 推入 \(q_2\) 的队尾,或把第二小的数据直接推入 \(q_2\) 的队尾,需要对这两种情况取 \(\max\)

\(n-1\) 次操作后,输出 \(q_2\) 的队头即可。


代码实现:

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

using namespace std;
queue<int> q1,q2;
signed a[(int)1e7+7],t[(int)1e7+7];

inline int max(int x,int y) { return x>y?x:y; }
inline int min(int x,int y) { return x<y?x:y; }

inline int get_first()//取两个队列对头的最小值
{
	if(q2.empty()||(!q1.empty()&&q1.front()<q2.front()))
	{//q1 的队头最小或 q2 为空
		int x=q1.front();
		q1.pop();
		return x;
	}
	//q2 的队头最小或 q1 为空
	int x=q2.front();
	q2.pop();
	return x;
}

void generate_array(signed a[], signed n, signed m, signed seed) {
	unsigned x = seed;
	for (int i = 1; i <= n; ++i) {
		x ^= x << 13;
		x ^= x >> 17;
		x ^= x << 5;
		a[i] = x % m + 1;
	}
}
signed n,m,seed;
signed main()
{
	scanf("%d%d%d",&n,&m,&seed);
	generate_array(a,n,m,seed);//构造数据
	for(register int i=1;i<=n;i++) t[a[i]]++;//桶排
	for(register int i=1,j=1;i<=10000000;i++)
	{
		if(t[i]) for(j=1;j<=t[i];j++) q1.push(i);
		//向 q1 中推入数据
	}
	
	for(register int i=1;i<n;i++)
	{
		int x=get_first();//第一次取队头的最小值
		int y=get_first();//第二次取队头的最小值
		q2.push(max(max(x,y),min(x,y)<<1));
		//对两种情况取 max
	}
	printf("%lld",q2.front());
	
	
	return 0;
}
posted @ 2025-02-08 16:36  Wy_x  阅读(16)  评论(0)    收藏  举报