洛谷3571 POI2014 SUP-Supercomputer (斜率优化)
一道神仙好题。
首先看到有多组\(k\),第一反应就是离线。
考虑贪心。
我们每次一定是尽量选择有儿子的节点。以便于我们下一次扩展。
但是对于一个\(k\),每次贪心的复杂度是\(O(n)\)
总复杂度是\(O(nq)\),肯定过不了。
qwq
那我们只能来考虑一个快速求一个\(k\)的答案。
感觉题解的柿子好神仙啊。
这里定义\(f[i]\)表示\(k=i\)的时候的最小次数。
\(sum[i]\)表示深度大于等于\(i\)的点有多少个。
则$$f[i]=max(j+\lceil \frac{sum[j+1]}{i} \rceil)$$
含义是用了\(i\)次把全\(i\)层都取掉,然后剩下的每次都能取满。
qwq现在来解释一下为什么是这个柿子。
首先,比较容易证明答案一定在所有的\((j+\lceil \frac{sum[j+1]}{i} \rceil\)中,因为这已经是最优情况了(前i次最多取i层,而后面也是每次取满,所以一定是最优的情况,不存在更优秀的情况。)
那么为什么是要取\(max\)呢。
是为了避免不合法的情况。
这里不合法的情况有两种情况,首先是前\(i\)次取不满\(前i层\)。那么如果存在这个情况,一定存在\(j\)使得,前\(j\)层能够\(j\)次取满,但是\(j到i\)不能用\(j-i\)取满,则存在等式
\]
\]
那么取\(max\),这种不合法的情况就能排除。
另一种不合法的情况就是,后面的次数并不能每次都取满。
如果上面的情况合法,那么一定存在$$\lceil \frac{sum[i+1]-sum[i+x+1]}{k} \rceil + i+x+1 > \lceil \frac{sum[i+1]}{k} \rceil + i$$
因为存在一层满足不能够一次用满k,且没有多余的东西让他选,那这时候等式左边的\(i+x+1\)等于该层的时候,一定比原本的柿子更大。
至于为什么不存在一个小于\(max\)并且合法的情况,是因为一层最少需要一次。而如果存在\(min\),说明要满足用小于\(j\)次,选完\(j\)层,而这个东西是不可能的。
qwq
那么证明到这里,大概能说明上述的柿子的是对的了。
也就是
\]
那接下来应该怎么优化呢。
我们将上述柿子进行变形
\]
那么如果存在一个\(j>k\)且\(j比k\)优秀的话,应该满足
\]
经过化简,$$\frac{sum[j+1]-sum[k+1]}{j-k}>-i$$
直接上斜率优化就好
\(sum\)数组可以直接通过前缀和求出来
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 1e6+1e2;
int sum[maxn];
int n,m;
int point[maxn],nxt[maxn],to[maxn];
int cnt;
int deep[maxn];
int dp[maxn];
int a[maxn];
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
struct Point{
ll x,y,num;
};
Point q[maxn];
ll chacheng(Point x,Point y)
{
return x.x*y.y-x.y*y.x;
}
bool Count(Point i,Point j,Point k)
{
Point x,y;
x.x=k.x-i.x;
x.y=k.y-i.y;
y.x=k.x-j.x;
y.y=k.y-j.y;
if (chacheng(x,y)>=0) return true;
return false;
}
int head=1,tail=0;
void push(Point x)
{
while(tail>=head+1 && Count(q[tail-1],q[tail],x)) tail--;
q[++tail]=x;
}
void pop(int lim)
{
while(tail>=head+1 && q[head+1].y-q[head].y>lim*(q[head+1].x-q[head].x)) head++;
}
int mx;
void dfs(int x,int dep)
{
deep[dep]++;
mx=max(mx,dep);
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
dfs(p,dep+1);
}
}
int qq;
int main()
{
n=read();qq=read();
int ymh =0;
for (int i=1;i<=qq;i++) a[i]=read(),ymh=max(ymh,a[i]);
for (int i=2;i<=n;i++)
{
int x=read();
addedge(x,i);
}
dfs(1,1);
for (int i=mx;i>=0;i--)
{
deep[i]+=deep[i+1];
}
for (int i=0;i<mx;i++)
push((Point){i,deep[i+1],i});
for (register int i=1;i<=ymh;++i)
{
pop((-1)*i);
int now = q[head].num;
dp[i]=now+((deep[now+1]-1)/i)+1;
}
for (int i=1;i<=qq;i++) cout<<dp[a[i]]<<" ";
return 0;
}
洛谷3571 POI2014 SUP-Supercomputer (斜率优化)的更多相关文章
- 洛谷P2365 任务安排(斜率优化dp)
传送门 思路: 最朴素的dp式子很好考虑:设\(dp(i,j)\)表示前\(i\)个任务,共\(j\)批的最小代价. 那么转移方程就有: \[ dp(i,j)=min\{dp(k,j-1)+(sumT ...
- 洛谷P2120 [ZJOI2007]仓库建设 斜率优化DP
做的第一道斜率优化\(DP\)QwQ 原题链接1/原题链接2 首先考虑\(O(n^2)\)的做法:设\(f[i]\)表示在\(i\)处建仓库的最小费用,则有转移方程: \(f[i]=min\{f[j] ...
- 【洛谷p3994】Highway 二分+斜率优化DP
题目大意:给你一颗$n$个点的有根树,相邻两个点之间有距离,我们可以从$x$乘车到$x$的祖先,费用为$dis\times P[x]+Q[x]$,问你除根以外每个点到根的最小花费. 数据范围:$n≤1 ...
- 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)
题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...
- 洛谷P4072 [SDOI2016]征途(斜率优化)
传送门 推式子(快哭了……)$$s^2*m^2=\sum _{i=1}^m (x_i-\bar{x})^2$$ $$s^2*m^2=m*\sum _{i=1}^m x_i^2-2*sum_n\sum ...
- 【洛谷 P5017】 摆渡车(斜率优化)
题目链接 算是巩固了一下斜率优化吧. 设\(f[i]\)表示前\(i\)分钟最少等待时间. 则有\(f[i]=\min_{j=0}^{i-m}f[j]+(cnt[i]-cnt[j])*i-(sum[i ...
- 洛谷P4983 忘情 (WQS二分+斜率优化)
题目链接 忘情水二分模板题,最优解对划分段数的导数满足单调性(原函数凸性)即可使用此方法. 详细题解洛谷里面就有,不啰嗦了. 二分的临界点让人有点头大... #include<bits/stdc ...
- 洛谷4072 SDOI2016征途 (斜率优化+dp)
首先根据题目中给的要求,推一下方差的柿子. \[v\times m^2 = m\times \sum x^2 - 2 \times sum \times sum +sum*sum \] 所以\(ans ...
- 洛谷 P3580 - [POI2014]ZAL-Freight(单调队列优化 dp)
洛谷题面传送门 考虑一个平凡的 DP:我们设 \(dp_i\) 表示前 \(i\) 辆车一来一回所需的最小时间. 注意到我们每次肯定会让某一段连续的火车一趟过去又一趟回来,故转移可以枚举上一段结束位置 ...
随机推荐
- Vue.JS快速上手(指令和实例方法)
1.声明式渲染 首先,我们要知道Vue是声明式渲染,那啥是声明式渲染,我们只需要告诉程序我们想要什么结果,其他的交给程序来做.与声明式渲染相对的是命令式渲染,即命令我们的程序去做什么,程序就会跟着你的 ...
- springboot中redis取缓存类型转换异常
异常如下: [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested ...
- Netty ServerBootstrap如何绑定端口
这篇讲netty服务端ServerBootstrap如何启动 前言 BootStrap在netty的应用程序中负责引导服务器和客户端.netty包含了两种不同类型的引导: 使用服务器的ServerBo ...
- Sentry-CLI 使用详解(2021 Sentry v21.8.x)
内容源于:https://docs.sentry.io/platforms/javascript/guides/vue/ 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创 ...
- 【曹工杂谈】说说Maven框架和插件的契约
说说Maven框架和插件的契约 前言 Maven框架就像现在公司内的各种平台方,规定一些契约,然后想办法拉动业务方,一起在这个平台上去做生态共建.Maven也是这样,其实它就是一个插件执行的框架,Ma ...
- 10分钟学会VS NuGet包私有化部署
前言 我们之前实现了打包发布NuGet,但是发布后的引用是公有的,谁都可以访问,显然这种方式是不可取的. 命令版本:10分钟学会Visual Studio将自己创建的类库打包到NuGet进行引用(ne ...
- Nginx:无处不在的Nginx的八个应用场景与配置
--- 阅读时间约 15 分钟 --- Nginx概述 众所周知,互联网已经离不开 WEB服务器 ,技术领域中 WEB服务器 不止 Nginx 一个,其他还有很多如 Apache . ...
- Linux残留的EFI启动项删除后又恢复的问题
电脑Windows + Fedora双系统,UEFI启动,共用同一个EFI分区.现在删除了Fedora系统,那么应该将EFI分区中的Fedora启动项也删除之. 按照网上的办法,在Windows上,尝 ...
- Object.keys( )与 for in 区别
for in 一般用于对象的遍历: let obj = { a:1, b:2, } for(let key in obj){ console.log(key) } // a // b Object.k ...
- Spring Cloud Eureka 之常用配置解析
[原创内容,转载.引用请注明出处] 1. 配置项解析 1.1 通用配置 # 应用名称,将会显示在Eureka界面的应用名称列 spring.application.name=config-servic ...