P2300 合并神犇

题目背景

loidc来到了NOI的赛场上,他在那里看到了好多神犇。

题目描述

神犇们现在正排成一排在刷题。每个神犇都有一个能力值p[i]。loidc认为坐在附近的金牌爷能力参差不齐非常难受。于是loidc便想方设法对神犇们进行人道主义合并。

loidc想把神犇的能力值排列成从左到右单调不减。他每次可以选择一个神犇,把他合并到两侧相邻的神犇上。合并后的新神犇能力值是以前两位犇的能力值之和。每次合并完成后,被合并的两个神犇就会消失。合并后的新神犇不能再分开(万一他俩有女朋友咋办)因此每次合并后神犇的总数会减1.

loidc想知道,想治好他的强迫症需要合并多少次

输入输出格式

输入格式:

第一行一个整数 n。

第二行 n 个整数,第 i 个整数表示 p[i]。

输出格式:

loidc需要合并的次数

说明

对于 50%的数据,0< n <=5000。

对于 100%的数据,0< n <=200000,0< p[i] <=2147483647,p 均为随机生成。


暴力数据结构万岁!!!

有一个纯贪心做法,详见大佬的博客

这里我们用暴力数据结构维护。

不难想到转移方程:

令\(dp[i]\)代表前\(i\)个人合并后的最小合并次数,\(f[i]\)代表前\(i\)个人在最小合并下的末尾元素,\(sum[i]\)为前缀和数组。

值得一提的是,这里有个贪心:即\(f[i]\)在\(dp[i]\)下一定取到最小。

转移:\(dp[i]=dp[k]+i-1-k,f[k]<=sum[i]-sum[k]\)

枚举\(k\)的话是\(O(n^2)\),这里搞个暴力数据结构维护一下。

将转移条件变形,\(sum[k]+f[k]<=sum[i]\),也就是说,我们每次询问值比\(sum[i]\)小的区间所代表的转移中的最小值即可。

在线段树上维护二元组\((dp[k]+n-k,k)\),第一组为第一关键字,求最小值,第二组为第二关键字,求最大值。

为什么求最大值?一个贪心,当\(dp[k]+n-k\)相等时,\(k\)越往后取,\(f[i]\)越小(或不变)。

然而区间可能开的很大,我们得想办法优化一下空间。

参照主席树的思想进行离散,我们可以对用不上的区间先不管,询问时或者改变时再加上即可。


code:

#include <cstdio>
#define LS t[id].ls
#define RS t[id].rs
#define Mid (ql+qr>>1)
typedef long long ll;
const int N=200010;
ll a[N],s[N],f[N];
int n,dp[N],root;
//dp[i]长度为i的合法序列最小合并
//f[i]长度为i的合法序列最小合并下的末尾最小大小
struct node2
{
int c,pos;
bool friend operator <(node2 n1,node2 n2)
{
if(n1.c!=n2.c) return n1.c<n2.c;
return n1.pos>n2.pos;
}
}inf;
node2 min(node2 x,node2 y){return x<y?x:y;}
struct node
{
int ls,rs;//子树
node2 c;
}t[30000002];//维护值在l,r区间内的最小dp[k]+n-k;
int tot=0,pos[N];
int add(ll l,ll r,node2 x)
{
t[++tot].c=x;
return tot;
}
node2 query(int id,ll ql,ll qr,ll l,ll r)
{
if(!id) return inf;
if(l==ql&&r==qr)
return t[id].c;
if(r<=Mid) return query(LS,ql,Mid,l,r);
else if(l>Mid) return query(RS,Mid+1,qr,l,r);
else return min(query(LS,ql,Mid,l,Mid),query(RS,Mid+1,qr,Mid+1,r));
}
int change(int id,ll ql,ll qr,ll x,node2 del)
{
if(!id) id=add(ql,qr,del);
if(ql==qr) return id;
if(Mid>=x) LS=change(LS,ql,Mid,x,del);
else RS=change(RS,Mid+1,qr,x,del);
t[id].c=min(t[id].c,del);
return id;
}
int main()
{
scanf("%d",&n);
inf.c=0x3f3f3f3f;
inf.pos=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
scanf("%lld",a+i);
s[i]=s[i-1]+a[i];
}
node2 cc;
cc.c=n,cc.pos=0;
root=add(0,s[n],cc);
change(root,0,s[n],0,cc);
pos[n]=0;
for(int i=1;i<=n;i++)
{
node2 j=query(1,0,s[n],0,s[i]);
dp[i]=j.c-1+i-n;
f[i]=s[i]-s[j.pos];
if(s[i]+f[i]<=s[n])
{
node2 tt;
tt.c=dp[i]+n-i;
tt.pos=i;
change(root,0,s[n],s[i]+f[i],tt);
}
}
printf("%d\n",dp[n]);
return 0;
}

2018.6.8

洛谷 P2300 合并神犇 解题报告的更多相关文章

  1. 洛谷 P2300 合并神犇

    洛谷 听说这题可以\(n^2\)水过去,不过这里介绍一种\(O(n)\)的做法. \(f[i]\)为第\(1-i\)位合并的次数. \(pre[i]\)为第\(1-i\)位最末尾的数. \(j\)为满 ...

  2. 洛谷P2300 合并神犇

    传送门啦 分析: 刚开始读完题后感觉很懵,怎么算都不是3,结果发现题目理解错了.题目要求的是求一个不降的序列,不是递减的(发现自己好傻) 看明白题就好做了吧.经典的区间dp题,合并果子大家应该都做过, ...

  3. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  4. DP——P2300 合并神犇

    题目背景 loidc来到了NOI的赛场上,他在那里看到了好多神犇. 题目描述 神犇们现在正排成一排在刷题.每个神犇都有一个能力值p[i].loidc认为坐在附近的金牌爷能力参差不齐非常难受.于是loi ...

  5. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  6. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  7. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

  8. 洛谷1303 A*B Problem 解题报告

    洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...

  9. 洛谷 P2389 电脑班的裁员 解题报告

    题意: 给定一段长为N的序列,选取其中的至多M段使这些子段和最大. 当N=1000时,我们可以采用动态规划解法 令\(dp[i][j][k]\)代表当前选至位置\(i\)处于第\(j\)段当前是否选取 ...

随机推荐

  1. Codeforces 718C solution

    C. Sasha and Array   time limit per test :  5 seconds memory limit per test :  256 megabytes Descrip ...

  2. Scala学习(七)---包和引入

    包和引入 摘要: 在本篇中,你将会了解到Scala中的包和引入语句是如何工作的.相比Java不论是包还是引入都更加符合常规,也更灵活一些.本篇的要点包括: 1. 包也可以像内部类那样嵌套 2. 包路径 ...

  3. GlusterFS分布式存储数据的恢复机制(AFR)的说明

    GlusterFSFS恢复数据都是基于副本卷来说的,GlusterFSFS复制卷是采用镜像的方式做的,并且是同步事务性操作.简单来说就是,某一个客户要写文件时,先把这个文件锁住,然后同时写两个或多个副 ...

  4. 针对负载均衡集群中的session解决方案的总结

    在日常运维工作中,当给Web站点使用负载均衡之后,必须面临的一个重要问题就是Session的处理办法,无论是PHP.Python.Ruby还是Java语言环境,只要使用服务器保存Session,在做负 ...

  5. Jenkins部署Python项目实战

    一.背景 我们工作中常用Jenkins部署Java代码,因其灵活的插件特性,例如jdk,maven,ant等使得java项目编译后上线部署一气呵成,同样对于脚本语言类型如Python上线部署,利用Je ...

  6. Linux内核分析第四章读书笔记

    第四章 进程调度 进程调度程序:确保进程能有效工作的一个内核子程序 决定将哪个进程投入运行,何时运行已经运行多长时间 进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统 原则:只 ...

  7. "留拍"-注册/登录详解

    1. 注册 打开 “留拍” 软件,进入 主页面 ,然后按 注册 按钮: 在注册页面什么内容 都没有写 上去的情况下,按 完成 按钮: 首先把URL封装起来: public class URL { pu ...

  8. 『编程题全队』Beta 阶段冲刺博客一

    1.提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID) (1) 昨天已完成的工作 孙志威: 1.讨论并制定了Beta阶段的计划 孙慧君: 1.Beta阶段任务的认领 黄华林 ...

  9. jQuery empty() vs remove()

    https://stackoverflow.com/questions/3090662/jquery-empty-vs-remove http://www.cnblogs.com/yeer/archi ...

  10. Activiti启动某个流程失败,页面报500

    现象:Activiti启动某个流程失败,页面报500,错误日志如下. 2017-06-19 10:50:09 [org.activiti.engine.impl.interceptor.Command ...