3675: [Apio2014]序列分割

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 1420  Solved: 583
[Submit][Status][Discuss]

Description

小H最近迷上了一个分隔序列的游戏。在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列。为了得到k+1个子序列,小H需要重复k次以下的步骤:
1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的序列——也就是一开始得到的整个序列);
2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新序列。
每次进行上述步骤之后,小H将会得到一定的分数。这个分数为两个新序列中元素和的乘积。小H希望选择一种最佳的分割方式,使得k轮之后,小H的总得分最大。

Input

输入第一行包含两个整数n,k(k+1≤n)。

第二行包含n个非负整数a1,a2,...,an(0≤ai≤10^4),表示一开始小H得到的序列。

Output

输出第一行包含一个整数,为小H可以得到的最大分数。

Sample Input

7 3
4 1 3 4 0 2 3

Sample Output

108

HINT

【样例说明】 
在样例中,小H可以通过如下3轮操作得到108分: 
1.-开始小H有一个序列(4,1,3,4,0,2,3)。小H选择在第1个数之后的位置 
将序列分成两部分,并得到4×(1+3+4+0+2+3)=52分。 
2.这一轮开始时小H有两个序列:(4),(1,3,4,0,2,3)。小H选择在第3个数 
字之后的位置将第二个序列分成两部分,并得到(1+3)×(4+0+2+3)=36分。 
3.这一轮开始时小H有三个序列:(4),(1,3),(4,0,2,3)。小H选择在第5个 
数字之后的位置将第三个序列分成两部分,并得到(4+0)×(2+3)=20分。 
经过上述三轮操作,小H将会得到四个子序列:(4),(1,3),(4,0),(2,3)并总共得到52+36+20=108分。 
【数据规模与评分】:

数据满足2≤n≤100000,1≤k≤min(n -1,200)。

Source

Solution

个人感觉比较神的题

首先需要发现一个性质:

割k次,只要割的是正确位置,那么答案与割的顺序无关

证明:

大体上假设某串为$abcd$,如果最后要分割成$a|b|cd$那么:

先分割成$ab|cd$当前答案为$a*cd+b*cd$,再分割成$a|b|cd$,答案为$a*b+a*cd+b*cd$

先分割成$a|bcd$当前答案为$a*bcd$,在分割成$a|b|cd$,答案为$a*bcd+b*cd$

那么两式化一化就可以发现得到的是相同的。所以,对于其余的也合适;

那么可以得出一个初步的转移:

$f[i][j]=max(f[j][k-1]+sum[j]*(sum[i]-sum[j]))$其中$f[i][j]$表示的是:前i个元素,分成k段的最大分数

那么可以进行一下斜率优化,最后化出的式子:$(dp[j'][k]-dp[i'][k]+sum[i']*sum[i']-sum[j']*sum[j'])/(sum[i']-sum[j'])<=sum[i]$

有一个额外的处理,如果$a[i]==0$那么它实际上是没有意义的,反而阻碍计算,那么可以直接扔掉

内存有点小,需要滚动数组,那么滚一下就好

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 100010
#define maxk 201
int n,K,a[maxn],que[maxn],l,r;
long long sum[maxn],dp[maxn][];
inline double slope(int i,int j,int k)
{
return double(dp[j][k]-dp[i][k]+sum[i]*sum[i]-sum[j]*sum[j])/double(sum[i]-sum[j]);
}
int main()
{
n=read(),K=read();
for (int i=; i<=n; i++)
{
a[i]=read();
if (a[i]==) {i--; n--; continue;}
sum[i]=sum[i-]+a[i];
}
for (int j=,k=; k<=K; k++,j^=,l=r=)
for (int tmp,i=k; i<=n; i++)
{
while (l<r && slope(que[l],que[l+],j^)<=sum[i]) l++;
tmp=que[l];
dp[i][j]=dp[tmp][j^]+(sum[i]-sum[tmp])*sum[tmp];
while (l<r && slope(que[r-],que[r],j^)>=slope(que[r],i,j^)) r--;
que[++r]=i;
}
printf("%lld\n",dp[n][K&]);
return ;
}

WA了好几次...调了好久QAQ

【BZOJ-3675】序列分割 DP + 斜率优化的更多相关文章

  1. BZOJ 3675: [Apio2014]序列分割( dp + 斜率优化 )

    WA了一版... 切点确定的话, 顺序是不会影响结果的..所以可以dp dp(i, k) = max(dp(j, k-1) + (sumn - sumi) * (sumi - sumj)) 然后斜率优 ...

  2. 【BZOJ3675】序列分割(斜率优化,动态规划)

    [BZOJ3675]序列分割(斜率优化,动态规划) 题面 Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得 ...

  3. BZOJ_3675_[Apio2014]序列分割_斜率优化

    BZOJ_3675_[Apio2014]序列分割_斜率优化 Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了 ...

  4. BZOJ 3675 [Apio2014]序列分割 (斜率优化DP)

    题目链接 BZOJ 3675 首先最后的答案和分割的顺序是无关的, 那么就可以考虑DP了. 设$f[i][j]$为做了$i$次分割,考虑前$j$个数之后的最优答案. 那么$f[i][j] = max( ...

  5. BZOJ 3675: 序列分割 (斜率优化dp)

    Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首 ...

  6. bzoj 3675: [Apio2014]序列分割【斜率优化dp】

    首先看这个得分方式,容易发现就相当于分k段,每段的值和两两乘起来. 这样就很容易列出dp方程:设f[i][j]为到j分成分成i段,转移是 \[ f[i][j]=max { f[k][j]+s[k]*( ...

  7. 【洛谷3648】[APIO2014] 序列分割(斜率优化DP)

    点此看题面 大致题意: 你可以对一个序列进行\(k\)次分割,每次得分为两个块元素和的乘积,求总得分的最大值. 区间\(DPor\)斜率优化\(DP\) 这题目第一眼看上去感觉很明显是区间\(DP\) ...

  8. P3648 [APIO2014]序列分割(斜率优化dp)

    P3648 [APIO2014]序列分割 我们先证明,分块的顺序对结果没有影响. 我们有一个长度为3的序列$abc$ 现在我们将$a,b,c$分开来 随意枚举一种分块方法,如$(ab)(c)$,$(a ...

  9. 2018.09.29 bzoj3675: [Apio2014]序列分割(斜率优化dp)

    传送门 斜率优化dp经典题目. 首先需要证明只要选择的K个断点是相同的,那么得到的答案也是相同的. 根据分治的思想,我们只需要证明有两个断点时成立,就能推出K个断点时成立. 我们设两个断点分成的三段连 ...

随机推荐

  1. Debian 8(Jessie) 安装pptp-linux (PPTP客户端), 以及route命令说明

    命令, 这里定义这个pptp的连接名称为hcoffice #安装 sudo apt-get install pptp-linux #用户名和口令 sudo vim /etc/ppp/chap-secr ...

  2. 学习jQuery的on事件

    开发asp.net mvc程序,多少是离不开jQuery客户程序.今天Insus.NET学习jQuery的一个on事件驱动. 先在网页视图放一个图片铵钮,用户可以使用mouse对这图片时行over,o ...

  3. Tomcat6配置webdav协议

    Tomcat6默认是支持webdav协议的,只是webapps目录中不带例子而已.要添加支持很简单,在webapps目录中建立webdav目录,在webdav目录中建立WEB-INF目录,加入web. ...

  4. Hibernate SQL Dialect 方言

    RDBMS Dialect DB2 org.hibernate.dialect.DB2Dialect DB2 AS/400 org.hibernate.dialect.DB2400Dialect DB ...

  5. TF400916错误修复办法

    在使用TFS作为研发过程管理工具的时候,如果调整了工作项的状态信息,可能会出现下面的错误: 要解决此问题非常简单: 1.找一台安装了VS2015程序的环境.因为我们使用的是TFS2015,所以需要对应 ...

  6. mSites and Smarty

    目前的页面实现方式是需要向后台请求接口,返回 JSON 数据,动态拼接字符串塞进 DOM 中(innerHTML).考虑用 Smarty 生成静态页面,可以在后台用 PHP 得到数据,字符串拼接,然后 ...

  7. SQL基础之select

    1.认识select select的主要语法如下,这个很重要因为只有记住了整体的结构才能应对任何情况.从中可以看到select的强大主要就是建立在where.group by.having.order ...

  8. TensorFlow 源代码初读感受

    把自己微博发的文章:http://www.weibo.com/1804230372/En7PdlgLb?from=page_1005051804230372_profile&wvr=6& ...

  9. [HDU5902]GCD is Funny(xjb搞)

    题意:n个数每次选三个数删除,取其中两个数将gcd放回去两次,问最后剩的数可能是多少 分析:考虑最优情况: 先拿出三个数,留下两个x,x  再来一个y,(x,x,y)我们可以删去一个x,留下两个gcd ...

  10. SQL复杂查询和视图

    子查询 现实中,很多情况下需要进行下述条件判断 某一元素是否是某一集合成员 某一集合是否包含另一集合 测试集合是否为空 测试集合是否存在另一元组 子查询是出现在WHERE子句中的SELECT语句被称为 ...