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;
}
以下是博客签名,正文无关
本文来自博客园,作者:Wy_x,转载请在文首注明原文链接:https://www.cnblogs.com/Wy-x/articles/18704570
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC-BY-NC-SA 4.0 协议)进行许可。

浙公网安备 33010602011771号