题目

描述





题目已经足够清晰了,所以不再赘述题目大意。


思考历程

一眼看下去,好像是一道大水题!

然而,再看几眼,感觉又不是一道水题!

然后想了半天,感觉它特别难转移!

最终打了一个暴力,然后发现样例没有过去!

调试一波,发现原因是恶心的编号……(为什么要设置成这样,好不习惯啊……)

最终交上去,5分!

我的暴力不应该30分吗?

欲哭无泪……


正解

这题的正解有一个很好的思想。

首先,显然这题是DP,因为数据太大,不能用网络流,贪心显然是错误的。

估计一下时间复杂度:O(NK)O(NK)O(NK)

如何做到优秀的转移?

感觉上,如果正着转移,那就比较麻烦;但是我们能不能考虑反着转移呢?

我们可以先将k=0k=0k=0的答案计算出来,

对于一段区间,就要减去它们之间的长度乘上区间左边的总数。

因为题目要求最小,所以我们计算出这个东西的最大值,然后减去它。

设fi,kf_{i,k}fi,k​表示现在到了iii这个点,放置了kkk个消防栓的最大值。

方程就出来了:fi,k←fj,k−1+Wj(Di−Dj)f_{i,k}\leftarrow f_{j,k-1}+W_j(D_i-D_j)fi,k​←fj,k−1​+Wj​(Di​−Dj​)

其中WiW_iWi​表示iii之前(含)的总数,DiD_iDi​表示从起点到iii的距离。

注意在实现的过程中的细节,什么加一减一之类的东西(调试时最可恶的东西就是这个了)。

这是一个O(N2K)O(N^2K)O(N2K)的做法,还是不够优秀。

再仔细观察一下式子,我们发现好像可以斜率优化!

然后斜率优化一下,时间复杂度就下降到O(NK)O(NK)O(NK)。

斜率优化怎么搞?我就不打算讲了,都是那样推式子,自己推去。

按道理来说这个时间其实是过得去的,可是数据坑爹,最后一个点特别恶心,卡常数都难卡过去。并且,这个数据本身就是错误的……所以说,如果你有了95分,恭喜你,实际上你已经AC了。

题解上还有一些比较奇怪的做法。

比如,当K=1K=1K=1时,三分放在哪个点,得出最优解。

如果K>1K>1K>1呢?那就是神一般的三分套三分……不停套下去,一共KKK层……

这个方法不得不说特别强悍……

也许是可以过的吧(说真的,我身边的同学没有一个人打这种奇葩做法)。

还有一种做法叫作模拟退火。

具体怎么做我就不说了,模拟退火的本质就是暴力……

而且这题还有SPJ,所以模拟退火据说可以水到很多的分数……

题解说期望97分……

当然,如果能打正解,就尽量打正解。模拟退火就应该看成一个水分神器,在某些时候,据说模拟退火可以切爆正解!

呜呜呜我不会模拟退火……


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000001
int n,K;
long long w[N+1],d[N+1],W[N+1],D[N+1];
long long ans0;
long long f[N+1][23];
int pre[N+1][23];
int q[N+1],head,tail;
inline bool calc1(int i,int a,int b,int k){
return (f[a][k]-W[a]*D[a])-(f[b][k]-W[b]*D[b])<=D[i]*(W[b]-W[a]);
}
inline bool calc2(int a,int b,int c,int k){
return ((f[a][k]-W[a]*D[a])-(f[b][k]-W[b]*D[b]))*(W[c]-W[b])>=((f[b][k]-W[b]*D[b])-(f[c][k]-W[c]*D[c]))*(W[b]-W[a]);
}
void print(int i,int k){
if (!i)
return;
print(pre[i][k],k-1);
printf("%d ",i-1);
}
int main(){
freopen("life.in","r",stdin);
freopen("life.out","w",stdout);
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&K);
for (int i=1;i<=n;++i)
scanf("%d%d",&w[i],&d[i]);
long long sum=0;
for (int i=1;i<=n;++i){
sum+=w[i];
ans0+=sum*d[i];
}
W[0]=0,D[0]=0;
for (int i=1;i<=n+1;++i)
W[i]=W[i-1]+w[i],D[i]=D[i-1]+d[i-1];
memset(f,128,sizeof f);
f[0][0]=0;
for (int k=1;k<=K+1;++k){
q[head=tail=0]=0;
for (int i=1;i<=n+1;++i){
while (head<tail && calc1(i,q[head],q[head+1],k-1))
++head;
f[i][k]=f[q[head]][k-1]+W[q[head]]*(D[i]-D[q[head]]);
pre[i][k]=q[head];
while (head<tail && calc2(q[tail-1],q[tail],i,k-1))
--tail;
q[++tail]=i;
}
}
printf("%lld\n",ans0-f[n+1][K+1]);
print(pre[n+1][K+1],K);
return 0;
}

我认为这个程序不需要打注释……


总结

其实这题的斜率优化真的是一点也不难(我不会告诉我在NOIP2018前一个星期才学会了斜率优化)。

这题最终要的地方是从反面求答案。

有时候反面求比正面求简单多了。

[JZOJ5355] 【NOIP2017提高A组模拟9.9】保命的更多相关文章

  1. JZOJ 100029. 【NOIP2017提高A组模拟7.8】陪审团

    100029. [NOIP2017提高A组模拟7.8]陪审团 Time Limits: 1000 ms  Memory Limits: 131072 KB  Detailed Limits   Got ...

  2. JZOJ 5328. 【NOIP2017提高A组模拟8.22】世界线

    5328. [NOIP2017提高A组模拟8.22]世界线 (File IO): input:worldline.in output:worldline.out Time Limits: 1500 m ...

  3. JZOJ 5329. 【NOIP2017提高A组模拟8.22】时间机器

    5329. [NOIP2017提高A组模拟8.22]时间机器 (File IO): input:machine.in output:machine.out Time Limits: 2000 ms M ...

  4. JZOJ 5307. 【NOIP2017提高A组模拟8.18】偷窃 (Standard IO)

    5307. [NOIP2017提高A组模拟8.18]偷窃 (Standard IO) Time Limits: 1000 ms Memory Limits: 262144 KB Description ...

  5. JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)

    5286. [NOIP2017提高A组模拟8.16]花花的森林 (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Descript ...

  6. JZOJ 5305. 【NOIP2017提高A组模拟8.18】C (Standard IO)

    5305. [NOIP2017提高A组模拟8.18]C (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Description ...

  7. 【NOIP2017提高A组模拟9.17】信仰是为了虚无之人

    [NOIP2017提高A组模拟9.17]信仰是为了虚无之人 Description Input Output Sample Input 3 3 0 1 1 7 1 1 6 1 3 2 Sample O ...

  8. 【NOIP2017提高A组模拟9.17】猫

    [NOIP2017提高A组模拟9.17]猫 题目 Description 信息组最近猫成灾了! 隔壁物理组也拿猫没办法. 信息组组长只好去请神刀手来帮他们消灭猫.信息组现在共有n 只猫(n 为正整数) ...

  9. 【NOIP2017提高A组模拟9.17】组合数问题

    [NOIP2017提高A组模拟9.17]组合数问题 题目 Description 定义"组合数"S(n,m)代表将n 个不同的元素拆分成m 个非空集合的方案数. 举个例子,将{1,2,3}拆分成2 个 ...

  10. 【NOIP2017提高A组模拟9.12】Arrays and Palindrome

    [NOIP2017提高A组模拟9.12]Arrays and Palindrome[SPJ] 题目 Description Input Output Sample Input 1 6 Sample O ...

随机推荐

  1. 剑指offer——27二叉树的镜像

    题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...

  2. MySQL初步理解,简易单表增删改查

    什么是数据库? 存储数据的仓库,本质是一个文件系统,封装了算法和文件之前数据的存储模式 阶段1:集合 数组 变量 缺点:数据存储在内存中,不能实现数据的持久化存储 阶段2:IO流 结合文件 .txt ...

  3. msSql Server 修复数据库

    --rz要替换为修复数据库DBCC CHECKTABLE ('rz'); use master declare @databasename varchar(255) set @databasename ...

  4. 2019 HDU 多校赛第二场 HDU 6598 Harmonious Army 构造最小割模型

    题意: 有n个士兵,你可以选择让它成为战士还是法师. 有m对关系,u和v 如果同时为战士那么你可以获得a的权值 如果同时为法师,你可以获得c的权值, 如果一个为战士一个是法师,你可以获得b的权值 问你 ...

  5. CentOS7开放防火墙端口

    ~~~~~~~~~~~~开放某个端口~~~~~~~~~~~~firewall-cmd --zone=public --add-port=6669/tcp --permanentfirewall-cmd ...

  6. luaj使用 方法签名规则 Cocos2dxLuaJavaBridge

    function AndroidHandler:getParamJson()     local args = {nil}     local ok,ret = luaj.callStaticMeth ...

  7. Linux 常用命令:解压缩篇

    前言 Linux常用命令中,有很多用于对文件的压缩或解压,本文将介绍这些解压缩命令中不常见却非常实用的用法. tar tar是linux中最常用的解压缩命令.tar命令可用于处理后缀名为tar,tar ...

  8. 三角形的实现和盒模型、层模型、浮动模型、定位、权重、margin问题

    相邻的border会平分所占的区域,出现一个斜线, .my_triangle{ width: 10px; height: 10px; background-color: blue; border-wi ...

  9. [转]spring入门(六)【springMVC中各数据源配置】

    在使用spring进行javaWeb开发的过程中,需要和数据库进行数据交换,为此要经常获取数据库连接,使用JDBC的方式获取数据库连接,使用完毕之后再释放连接,这种过程对系统资源的消耗无疑是很大的,这 ...

  10. Perl 环境安装

    Perl 环境安装 在我们开始学习 Perl 语言前,我们需要先安装 Perl 的执行环境. Perl 可以在以下平台下运行: Unix (Solaris, Linux, FreeBSD, AIX, ...