一道神仙好题。

首先看到有多组\(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\)取满,则存在等式

\[\lceil \frac{sum[j+1]}{k} \rceil > \lceil \frac{sum[i+1]}{k} \rceil + (i-j)
\]
\[\lceil \frac{sum[j+1]}{k} \rceil + j> \lceil \frac{sum[i+1]}{k} \rceil + 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

那么证明到这里,大概能说明上述的柿子的是对的了。

也就是

\[f[i]=max(j+\lceil \frac{sum[j+1]}{i} \rceil)
\]

那接下来应该怎么优化呢。

我们将上述柿子进行变形

\[f[i]=max(\lceil \frac{j\times i+ sum[j+1]}{i} \rceil)
\]

那么如果存在一个\(j>k\)且\(j比k\)优秀的话,应该满足

\[j\times i + sum[j+1] > k \times i + sum[k+1]
\]

经过化简,$$\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 (斜率优化)的更多相关文章

  1. 洛谷P2365 任务安排(斜率优化dp)

    传送门 思路: 最朴素的dp式子很好考虑:设\(dp(i,j)\)表示前\(i\)个任务,共\(j\)批的最小代价. 那么转移方程就有: \[ dp(i,j)=min\{dp(k,j-1)+(sumT ...

  2. 洛谷P2120 [ZJOI2007]仓库建设 斜率优化DP

    做的第一道斜率优化\(DP\)QwQ 原题链接1/原题链接2 首先考虑\(O(n^2)\)的做法:设\(f[i]\)表示在\(i\)处建仓库的最小费用,则有转移方程: \(f[i]=min\{f[j] ...

  3. 【洛谷p3994】Highway 二分+斜率优化DP

    题目大意:给你一颗$n$个点的有根树,相邻两个点之间有距离,我们可以从$x$乘车到$x$的祖先,费用为$dis\times P[x]+Q[x]$,问你除根以外每个点到根的最小花费. 数据范围:$n≤1 ...

  4. 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)

    题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...

  5. 洛谷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 ...

  6. 【洛谷 P5017】 摆渡车(斜率优化)

    题目链接 算是巩固了一下斜率优化吧. 设\(f[i]\)表示前\(i\)分钟最少等待时间. 则有\(f[i]=\min_{j=0}^{i-m}f[j]+(cnt[i]-cnt[j])*i-(sum[i ...

  7. 洛谷P4983 忘情 (WQS二分+斜率优化)

    题目链接 忘情水二分模板题,最优解对划分段数的导数满足单调性(原函数凸性)即可使用此方法. 详细题解洛谷里面就有,不啰嗦了. 二分的临界点让人有点头大... #include<bits/stdc ...

  8. 洛谷4072 SDOI2016征途 (斜率优化+dp)

    首先根据题目中给的要求,推一下方差的柿子. \[v\times m^2 = m\times \sum x^2 - 2 \times sum \times sum +sum*sum \] 所以\(ans ...

  9. 洛谷 P3580 - [POI2014]ZAL-Freight(单调队列优化 dp)

    洛谷题面传送门 考虑一个平凡的 DP:我们设 \(dp_i\) 表示前 \(i\) 辆车一来一回所需的最小时间. 注意到我们每次肯定会让某一段连续的火车一趟过去又一趟回来,故转移可以枚举上一段结束位置 ...

随机推荐

  1. 解析ThreadPoolExecutor类是如何保证线程池正确运行的

    摘要:对于线程池的核心类ThreadPoolExecutor来说,有哪些重要的属性和内部类为线程池的正确运行提供重要的保障呢? 本文分享自华为云社区<[高并发]通过源码深度解析ThreadPoo ...

  2. MySQL——主从复制

    ---- 高可用 ---- 辅助备份 ---- 分担负载 复制是MySQL的一项功能,允许服务器将更改从一个实例复制到另一个实例. --主服务器将所有数据和结构更改记录到二进制日志中. --从属服务器 ...

  3. Python__Xpath模块

    import requests from lxml import etree # 导入xpath headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6 ...

  4. 第九章 Net 5.0 快速开发框架 YC.Boilerplate --定时服务 Quartz.net

    在线文档:http://doc.yc-l.com/#/README 在线演示地址:http://yc.yc-l.com/#/login 源码github:https://github.com/linb ...

  5. [Elasticsearch] ES更新问题踩坑记录

    问题描述 我们有个系统设计的时候针对Hive创建表.删除表, 需要更新ES中的一个状态,标记是否删除,在几乎同时执行两条下面的语句的时候,发现在ES 中出现表即使被创建了还是无法被查询到的情况,针对该 ...

  6. Python - 面向对象编程 - 魔术方法(双下划线方法)

    什么是魔术方法 在Python中,所有以 __ 双下划线包起来的方法,都统称为 Magic Method 魔术方法,也叫双下划线方法 有哪些重要的魔术方法? __new__ https://www.c ...

  7. app自动化定位:UIautomation的用法

    UIautomation定位的优点: 速度比xpath定位快,UIautomation是Android的工作引擎 缺点: 没有idea提示 UIautomation使用方法: AndroidDrive ...

  8. Delphi使用Zxing创建二维码

    效果 DelphiZXingQRCode下载地址:https://www.debenu.com/open-source/delphizxingqrcode/ 为了调用方便unit DelphiZXIn ...

  9. Git:git commit时退出报错解决(Error45、Error325)

    Git 报错 在输入git commit编辑注释日志时强制退出git程式,文件会变成只读文件,于是出现下述报错: 解决方法(ERROR45) 我们提交代码的正常操作流程一般是: 输入git commi ...

  10. CentOS获取公网IP

    Curl 纯文本格式输出: curl icanhazip.com curl ifconfig.me curl curlmyip.com curl ip.appspot.com curl ipinfo. ...