Solution -「LOCAL」Drainage System
\(\mathcal{Description}\)
合并果子,初始果子的权值在 \(1\sim n\) 之间,权值为 \(i\) 的有 \(a_i\) 个。每次可以挑 \(x\in[L,R]\) 个果子合并成一个,代价为所挑果子权值之和。求合并所有果子的最少代价。\(T\) 组数据。
\(T\le10\),\(n,a_i\le10^5\),\(2\le L\le R\le\sum_{i=1}^na_i\)。
\(\mathcal{Solution}\)
把合并考虑成一棵树,树叉在 \([L,R]\) 内,可以发现总代价为每个点的深度 \(\times\) 权值之和。以此为背景证明几个结论(当然很容易直接猜到最终结论)。
Lemma 1:最优解的非叶结点最少。否则,一定可以删除最深的非叶结点,并把它的儿子们丢给其它非叶结点,使“深度 \(\times\) 权值之和”变小。
Lemma 2:记 \(u\) 的深度为 \(d(u)\),当树满足 Lemma 1 时,若存在非叶结点 \(d(u)<d(v)\),则 \(u\) 满叉。很显然,只要 \(v\) 存在且 \(u\) 不满,就可以把 \(v\) 的儿子接到 \(u\) 下使答案更优。由此有推论:存在最优解,其合并数量构成的序列字典序最小(先最小(\(L\)),再最大 \(R\))。
考虑到实际问题,我们可以断言答案的合并数量为:\(\{L,L,\cdots,L,x,R,R,\cdots,R\}\) 且其中 \(R\) 尽可能多。
不过这个题你甚至不能带堆的 \(\log\) qwq!
由输入方式,显然一堆果子可以表示成 \((\text{权值},\text{个数})\) 二元组,初始时有 \(n\) 个二元组(有些个数是 \(0\),用于占位),它们已按权值升序排列了。考虑从队首取出若干个小果子合并成大果子,显然和出的大果子的权值是升序的,那么很多情况下大果子可以直接插在队尾。不过可能有大果子的权值属于 \([1,n]\) 的情况,我们直接把对应果子的个数 \(+1\) 即可。
复杂度 \(\mathcal O(Tn\log\sum_{i=1}^na_i)\)。(Tiw 说的 qwq。
\(\mathcal{Code}\)
#include <queue>
#include <cstdio>
#include <iostream>
typedef long long LL;
typedef std::pair<LL, LL> pll;
inline char fgc () {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p ++;
}
inline LL rint () {
LL x = 0; char s = fgc ();
for ( ; s < '0' || '9' < s; s = fgc () );
for ( ; '0' <= s && s <= '9'; s = fgc () ) x = x * 10 + ( s ^ '0' );
return x;
}
const int MAXN = 1e5;
int n, a[MAXN + 5];
LL L, R, S, ans;
std::queue<pll> plan;
struct GreadyQueue {
std::deque<pll> deq;
std::deque<pll>::iterator ptr;
GreadyQueue (): ptr ( deq.end () ) {}
inline void clear () { deq.clear (), ptr = deq.end (); }
inline pll& front () { return deq.front (); }
inline void popF () {
bool eff = ptr == deq.begin ();
deq.pop_front ();
if ( eff ) ptr = deq.begin ();
}
inline void add ( const pll x ) {
ans += x.first * x.second;
for ( ; ptr != deq.end () && ptr->first < x.first; ++ ptr );
if ( ptr == deq.end () ) deq.push_back ( x ), -- ( ptr = deq.end () );
else ptr->second += x.second;
}
} Q;
inline void clear () {
ans = S = 0, Q.clear ();
for ( ; !plan.empty (); plan.pop () );
}
inline bool calcPlan () {
LL tR = ( S - 1 ) / ( R - 1 ) + !!( ( S - 1 ) % ( R - 1 ) ), tL = 0;
if ( tR * ( L - 1 ) > S - 1 ) return false;
LL def = tR * ( R - 1 ) - ( S - 1 );
if ( L ^ R ) {
tR -= tL = def / ( R - L ), def -= tL * ( R - L );
if ( tL ) plan.push ( pll ( L, tL ) );
if ( def ) plan.push ( pll ( R - def, 1 ) ), -- tR;
}
if ( tR ) plan.push ( pll ( R, tR ) );
return true;
}
inline void followPlan () {
for ( ; !plan.empty (); plan.pop () ) {
pll stp ( plan.front () ), cur ( 0, 0 );
while ( stp.second ) {
if ( cur.second ) {
if ( cur.second + Q.front ().second >= stp.first ) {
cur.first += Q.front ().first * ( stp.first - cur.second );
Q.front ().second -= stp.first - cur.second;
Q.add ( pll ( cur.first, 1 ) ), cur = pll ( 0, 0 );
-- stp.second;
} else {
cur.first += Q.front ().second * Q.front ().first;
cur.second += Q.front ().second, Q.popF ();
continue;
}
}
LL cnt = std::min ( stp.second, Q.front ().second / stp.first );
if ( cnt ) Q.add ( pll ( Q.front ().first * stp.first, cnt ) );
stp.second -= cnt, Q.front ().second -= stp.first * cnt;
if ( stp.second ) {
cur = pll ( Q.front ().second * Q.front ().first, Q.front ().second );
Q.popF ();
}
}
}
}
int main () {
freopen ( "river.in", "r", stdin );
freopen ( "river.out", "w", stdout );
for ( int T = rint (); T --; ) {
clear ();
n = rint (), L = rint (), R = rint ();
for ( int i = 1; i <= n; ++ i ) {
Q.deq.push_back ( pll ( i, a[i] = rint () ) );
S += a[i];
}
if ( !calcPlan () ) { puts ( "-1" ); continue; }
Q.ptr = Q.deq.begin (), followPlan ();
printf ( "%lld\n", ans );
}
return 0;
}
\(\mathcal{Details}\)
用 std::deque 是因为只有它有迭代器啦 owo。
涉及容器元素变化(特别是 pop,erase 之类)的时候,特别注意迭代器的操作嗷!
Solution -「LOCAL」Drainage System的更多相关文章
- Solution -「LOCAL」二进制的世界
\(\mathcal{Description}\) OurOJ. 给定序列 \(\{a_n\}\) 和一个二元运算 \(\operatorname{op}\in\{\operatorname{ ...
- Solution -「LOCAL」大括号树
\(\mathcal{Description}\) OurTeam & OurOJ. 给定一棵 \(n\) 个顶点的树,每个顶点标有字符 ( 或 ).将从 \(u\) 到 \(v\) ...
- Solution -「LOCAL」过河
\(\mathcal{Description}\) 一段坐标轴 \([0,L]\),从 \(0\) 出发,每次可以 \(+a\) 或 \(-b\),但不能越出 \([0,L]\).求可达的整点数. ...
- Solution -「LOCAL」Burning Flowers
灼之花好评,条条生日快乐(假装现在 8.15)! \(\mathcal{Description}\) 给定一棵以 \(1\) 为根的树,第 \(i\) 个结点有颜色 \(c_i\) 和光亮值 ...
- Solution -「LOCAL」画画图
\(\mathcal{Description}\) OurTeam. 给定一棵 \(n\) 个点的树形随机的带边权树,求所有含奇数条边的路径中位数之和.树形生成方式为随机取不连通两点连边直到全 ...
- Solution -「LOCAL」ZB 平衡树
\(\mathcal{Description}\) OurOJ. 维护一列二元组 \((a,b)\),给定初始 \(n\) 个元素,接下来 \(m\) 次操作: 在某个位置插入一个二元组: 翻 ...
- Solution -「LOCAL」舟游
\(\mathcal{Description}\) \(n\) 中卡牌,每种三张.对于一次 \(m\) 连抽,前 \(m-1\) 次抽到第 \(i\) 种的概率是 \(p_i\),第 \(m\) ...
- Solution -「LOCAL」充电
\(\mathcal{Description}\) 给定 \(n,m,p\),求序列 \(\{a_n\}\) 的数量,满足 \((\forall i\in[1,n])(a_i\in[1,m])\l ...
- Solution -「LOCAL」「cov. 牛客多校 2020 第五场 C」Easy
\(\mathcal{Description}\) Link.(完全一致) 给定 \(n,m,k\),对于两个长度为 \(k\) 的满足 \(\left(\sum_{i=0}^ka_i=n\r ...
随机推荐
- spring boot热部署 -- 实现 后端java热更新 -- 详细操作 【idea 的 JRebel破解】
1.前言 上一随笔写了如何使得spring boot热更新前端 ,但后端java部分无法热更新. 对于Java热更新,以前常使用 springloaded ,但是缺点 和bug很多 无法实现真正意 ...
- react子组件向父组件传值
子组件向父组件传值,注意父组件传递函数的时候必须绑定this到当前父组件(handleEmail={this.handleEmail.bind(this)}),不然会报错 /***实现在输入框输入邮箱 ...
- Python常用功能函数系列总结(七)
本节目录 常用函数一:批量文件重命名 常用函数一:批量文件重命名 # -*- coding: utf-8 -*- """ DateTime : 2021/02/08 10 ...
- Android官方文档翻译 十二 3.Supporting Different Devices
Supporting Different Devices 支持不同设备 Dependencies and prerequisites 依赖关系和先决条件 Android 1.6 or higher A ...
- .Net Core依赖注入
一.配置文件的读取 利用Startup类中的configuration读取appsettings.json中的配置 { "Logging": { "LogLevel&qu ...
- sqoop如何指定pg库的模式
摘要:sqoop如何指定pg库的模式? 本文分享自华为云社区<[Hadoop]关于Sqoop导出数据到postgresql时schema的设置问题>,作者:Copy工程师 . 说明 使用s ...
- strace -cp 诊断
strace -c php do.php 各项含义如下: - % time:执行耗时占总时间百分比 - seconds:执行总时间 - usecs/call:单个命令执行时间 - calls:调用次数 ...
- How to check in Windows if you are using UEFI
You might be wondering if Windows is using UEFI or the legacy BIOS, it's easy to check. Just fire up ...
- python23day
内容回顾 面向对象 类:是具有相同属性和相似功能的一类事物 对象/实例:具体的,一类可以有多个对象 实例化 练习 # 定义一个圆形类,半径是这个圆的属性,实例化一个半径为5的圆形,一个半径为10的圆形 ...
- Element Plus 正式版发布啦!🎉🎉
今天,我们非常高兴地宣布 Element Plus 稳定版正式发布.自第一个 commit 起,经过 1 年零 7 个月的持续迭代开发,总计 2635 commits,经过 256 位贡献者所提交的 ...