不一样做法的题解
Carey_chen · · 题解
这是一道数据结构优化贪心题。
对于
考虑优化这个过程,不难发现,由于每次被合并的两堆果子必然越来越大,每次新的果子堆的大小也必然单调不降。
考虑使用指针和链表来完成,不断向后扫描果堆并插入。
时间复杂度证明
排序使用桶排序,
每次合并两堆果子,需要扫描链表插入一个新节点,但扫描指针只向后移动,所以每个节点最多被扫描一次。
由于合并
总时间复杂度
代码
STL list 常数比较大,要使用手写链表。
一个很丑的实现:
#include <bits/stdc++.h>
using namespace std;
struct List
{
struct Node
{
long long a;
int l, r;
};
int pos = 1, siz = 0, len = 0, back = 0;
Node a[20000010];
int begin()
{
return pos;
}
void insert(int pos, long long x)
{
siz++;
len++;
a[siz].a = x;
a[siz].l = a[pos].l;
a[siz].r = pos;
a[a[siz].l].r = siz;
a[pos].l = siz;
}
void push_back(long long x)
{
len++;
siz++;
a[siz].a = x;
a[siz].l = back;
if(back != 0)
{
a[back].r = siz;
}
back = siz;
}
long long front()
{
return a[pos].a;
}
long long front_nxt()
{
return a[a[pos].r].a;
}
void pop_front()
{
len--;
pos = a[pos].r;
a[pos].l = 0;
}
int size()
{
return len;
}
};
int bkt[100010];
List K;
int read(){...} // 快读
int main()
{
// freopen("P6033_3.in", "r", stdin);
int n;
long long ans = 0;
n = read();
for(int i = 1; i <= n; i++)
{
bkt[read()]++;
}
for(int i = 1; i <= 100000; i++)
{
while(bkt[i] > 0)
{
K.push_back(i);
bkt[i]--;
}
}
auto pos = K.begin(); // pos 的位置是单调不降的
while(K.size() >= 2)
{
long long a = K.front(), b = K.front_nxt();
long long c = a + b;
ans += c;
bool OK = false;
while(1)
{
if(K.a[pos].a > c)
{
K.insert(pos, c);
OK = true;
break;
}
if(K.a[pos].r != 0)
{
pos = K.a[pos].r; // 这一句只会执行 O(n) 次
}
else
{
break;
}
}
if(!OK)
{
K.push_back(c);
}
K.pop_front();
K.pop_front();
}
printf("%lld", ans);
return 0;
}