P6033 合并果子 加强版
思路
其实我是在知道这道题要用单调队列做的前提下做的。
不过那也没什么关系,zhizhang的我还是调了一万年才调出来,然而最后一个点还\(TLE\)了。心态很炸裂,看了眼题解才发现,不能用\(sort\),改成桶排就\(A\)了。
思路非常简单,搞两个队列,一个用来存储初始的序列,而另一个用来存储每次合并之后的果子。很显然,两个队列都是单调递增的,所以每次只需要判断每个队列的前两个元素之和和分别取出队首的和哪个小就行了。这么简单的思路,实现和调试却花费了我一个小时。因为它要做到取出队列里第二个元素,而且还要分三种情况来还原和弹出,反正很恶心,写了一百多行,一交还\(T\)了。发现是\(sort\)时间复杂度炸了,还好不是算法错了。结果题解四五十行就\(A\)了,发现是我单调队列写麻烦了,就记录一下我冗长的代码吧。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
queue<ll> q1;
queue<ll> q2;
ll n,ans,x1,x2,y,y2,tot,sum1,sum2,sum3,inf=10000000000000;
bool f1,f2,f3;
ll a[10000005],sum[1000005];
inline void first(){
ans+=sum1;
q1.pop();
x1=inf;
x2=inf;
q2.push(sum1);
if(!q1.empty()){
x1=q1.front();
q1.pop();
}
if(!q1.empty()){
x2=q1.front();
}
if(y==inf){
y=sum1;
q2.pop();
return;
}
else if(y2==inf){
y2=sum1;
}
}
inline void second(){
ans+=sum2;
q2.push(sum2);
x1=inf;
y=inf;
x2=inf;
y2=inf;
if(!q1.empty()){
x1=q1.front();
q1.pop();
}
if(!q1.empty()){
x2=q1.front();
}
if(!q2.empty()){
y=q2.front();
q2.pop();
}
if(!q2.empty()){
y2=q2.front();
}
}
inline void third(){
ans+=sum3;
q2.push(sum3);
q2.pop();
y=inf;
y2=inf;
if(!q2.empty()){
y=q2.front();
q2.pop();
}
if(!q2.empty()){
y2=q2.front();
}
}
inline void qpop(){
sum1=x1+x2,sum2=x1+y,sum3=y+y2;
f1=0,f2=0,f3=0;
if(sum1>inf){
f1=1;
}
if(sum2>inf){
f2=1;
}
if(sum3>inf){
f3=1;
}
if(f2==1&&f1==1){
third();
return;
}
if(f2==1&&f3==1){
first();
return;
}
if(f1==1&&f3==1){
second();
return;
}
if(f1==1){
if(sum2<=sum3){
second();
return;
}
else{
third();
return;
}
}
if(f2==1){
if(sum1<=sum3){
first();
return;
}
else{
third();
return;
}
}
if(f3==1){
if(sum1<=sum2){
first();
return;
}
else{
second();
return;
}
}
if(f1!=1&&f2!=1&&f3!=1){
if(sum1<=sum2&&sum1<=sum3){
first();
return;
}
else if(sum2<=sum1&&sum2<=sum3){
second();
return;
}
else if(sum3<=sum1&&sum3<=sum2){
third();
return;
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
sum[a[i]]++;
}
for(ll i=1;i<=100000;i++){
while(sum[i]>0){
sum[i]--;
q1.push(i);
}
}
x1=inf,x2=inf,y=inf,y2=inf;
if(!q1.empty()){
x1=q1.front();
q1.pop();
}
if(!q1.empty()){
x2=q1.front();
}
if(!q2.empty()){
y=q2.front();
q2.pop();
}
if(!q2.empty()){
y2=q2.front();
}
while(tot<n-1){
qpop();
tot++;
}
printf("%lld\n",ans);
return 0;
}