3675: [Apio2014]序列分割

来源:互联网 发布:倍投软件下载 编辑:程序博客网 时间:2024/05/17 09:12

3675: [Apio2014]序列分割

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 1891  Solved: 776
[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

[Submit][Status][Discuss]

先画画图,设几个变量写一写,很容易发现,分割序列的顺序不影响答案
假设我们把序列分割成了k段,第i段序列的数值和是ai
那么ans = ∑ai*∑aj  (i∈[1,n) && j∈(i,n])
通过这个式子可以发现,第j段对ans的贡献是aj*∑ai(i∈[1,j))
那么维护一个前缀和数组sum
令f[i][j]:第j段最右边那个数字刚好是ai,得到的最大分数
因为我们用aj*∑ai(i∈[1,j))统计,后面还没处理到的位置可以先放着不管

那么f[i][j] = max{f[k][j-1] + sum[j]*(sum[i] - sum[j])}
把这个式子拆一下,弄成斜率优化的形式

然后这题比较,,,,,
因为数字非负,所以斜率的分母可能为0,也就是斜率变为∞
那么就只好将每个状态抽象成点,用向量来搞这题啦,,,(第一次写,自己调了好久GG)

最后是,这里面涉及到的不等关系一定要加上等号(即<= 或 >=),也就是两个地方转移的效果是一样时,优先保留后面的,因为根据原本的不等关系,后面的发展前景更广阔~
#include<iostream>#include<cstdio>#include<queue>#include<vector>#include<bitset>#include<algorithm>#include<cstring>#include<map>#include<stack>#include<set>#include<cmath>#include<ext/pb_ds/priority_queue.hpp>using namespace std;const int maxn = 1E5 + 10;typedef long long LL;struct Point{LL x,y;Point(){}Point(LL x,LL y): x(x),y(y){}Point operator - (const Point b) {return Point(x - b.x,y - b.y);}}p[2][maxn];typedef Point Vector;int n,k,head,tail,cur,Q[maxn];LL Ans,sum[maxn],f[2][maxn];LL Cross(Vector v1,Vector v2) {return v1.x*v2.y - v2.x*v1.y;}LL Work(int j,int i) {return f[cur^1][j] + sum[j]*(sum[i] - sum[j]);}bool Judge(int j,int t,int i){Point poi = p[cur^1][t] - p[cur^1][j];if (poi.x < 0)poi.x *= -1,poi.y *= -1;return poi.y >= -poi.x*sum[i];}bool judge(int j,int t,int i){Vector A = p[cur^1][t] - p[cur^1][j];Vector B = p[cur^1][i] - p[cur^1][t];return Cross(A,B) >= 0;}int getint(){char ch = getchar();int ret = 0;while (ch < '0' || '9' < ch) ch = getchar();while ('0' <= ch && ch <= '9')ret = ret*10 + ch - '0',ch = getchar();return ret;}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);#endifn = getint(); k = getint();for (int i = 1; i <= n; i++)sum[i] = getint(),sum[i] += sum[i-1];for (int i = 1; i <= n; i++)p[cur][i] = Point(sum[i],f[cur][i] - sum[i]*sum[i]);for (int t = 2; t <= k + 1; t++) {Q[head = tail = 1] = t - 1;cur ^= 1;for (int i = t; i <= n; i++) {while (head < tail && Judge(Q[head],Q[head+1],i))++head;LL now = Work(Q[head],i);while (head < tail && judge(Q[tail-1],Q[tail],i))--tail;Q[++tail] = i;f[cur][i] = now;p[cur][i] = Point(sum[i],f[cur][i] - sum[i]*sum[i]);}}cout << f[cur][n];return 0;}

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 如果父母是教师怎么办 老人档案丢了怎么办 想离婚想要孩子怎么办 一二年级成绩差怎么办 高考复读又失败怎么办 孩子不想估成绩怎么办 手机信号被屏蔽了怎么办 西安市旅游年卡怎么办 广电宽带网速慢怎么办 电视智能卡坏了怎么办 家乐卡二次授信怎么办? 邢台银行倒闭了怎么办 不敢和导师交流怎么办 考上一个破大学怎么办 腻子粉检测报告怎么办 电子厂插件很慢怎么办 预付费电表跳闸怎么办 电费有疑问怎么办大连 农村电表箱坏了怎么办 农村电表没电怎么办 家里电费特别高怎么办 电表读卡失败怎么办 电表卡消磁了怎么办 智能表采集失败怎么办 电脑没有蓝牙功能怎么办 判决后无力偿还怎么办 dz47-63c63跳闸怎么办 租房合同丢了怎么办 北京土地承包合同丢失怎么办 租赁合同丢失了怎么办 房屋租赁合同丢失怎么办 学校没发学生证怎么办 学校银行卡丢了怎么办 报税名字忘了怎么办 地税零申报漏报怎么办 欠中联重科施工电梯钱怎么办 大型船舶起锚正横后怎么办 老师不会教孩子怎么办 个体工商营业证怎么办 广州市住房公积怎么办 苹果账号禁用了怎么办