博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
3675: [Apio2014]序列分割
阅读量:5266 次
发布时间:2019-06-14

本文共 1533 字,大约阅读时间需要 5 分钟。

Description

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

1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的序列——也就是一开始得到的整个序列);

2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新序列。

每次进行上述步骤之后,小H将会得到一定的分数。这个分数为两个新序列中元素和的乘积。小H希望选择一种最佳的分割方式,使得k轮之后,小H的总得分最大。


随手列个柿子就会发现断点的选择顺序对于答案是没有影响的

\(f_{ij}\)表示前i个数字里加了j个断点的最大贡献

\[f_{i,j}=max(f_{i-1,k}+sum_k\times (sum_i-sum_k))(k< i)\]

\(f\)表示\(f_{i-1}\)(。。。

那么对于\(k\)\(l\)更优当且仅当

\[f_k+sum_k\times (sum_i-sum_k)>f_l+sum_l\times (sum_i-sum_l)\]

\[s_i>\frac{sum_l^2-sum_k^2+f_l-f_k}{s_l-s_k}\]

斜率优化!!


#include
#include
#include
#define M 110001#define LL long long using namespace std;int u,m,n,k,q[M],t,h,pre[M][210];LL f[2][M],s[M];double xl(int k,int l,int u){ if(s[k]==s[l]) return -1e18; return (1.0*(long double)(-f[u][l]+f[u][k]-((long double)s[k]*s[k])+((long double)s[l]*s[l]))*1.0/((long double)1.0*(-s[k]+s[l])));}int main(){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&m),s[i]=(LL)s[i-1]+m; for(int j=1;j<=k;j++) { h=t=0; u=j&1; for(int i=1;i<=n;i++) { while(t>h && xl(q[h+1],q[h],!u)<=(long double)s[i]) h++; int x=q[h]; pre[i][j]=x; f[u][i]=f[!u][x]+s[x]*(s[i]-s[x]); while(t>h && xl(q[t],q[t-1],!u)>=xl(i,q[t],!u)) t--; q[++t]=i; } } printf("%lld\n",f[k&1][n]); LL x=n; for(LL i=k;i>=1;i--) { printf("%lld ",pre[x][i]); x=pre[x][i]; }}

转载于:https://www.cnblogs.com/ZUTTER/p/10279645.html

你可能感兴趣的文章
ActiveMQ笔记之点对点队列(Point-to-Point)
查看>>
继承和多态
查看>>
Dijkstra+计算几何 POJ 2502 Subway
查看>>
修复IE不能执行JS的方法
查看>>
程序员究竟该如何提高效率zt
查看>>
希尔排序法(缩小增量法)
查看>>
PHP编程基础学习(一)——数据类型
查看>>
MongoDB-JAVA-Driver 3.2版本常用代码全整理(2) - 查询
查看>>
NPOI处理Word文本中上下角标
查看>>
Android笔记 Handler
查看>>
如何阅读大型前端开源项目的源码(转)
查看>>
java.util.Arrays类详解
查看>>
idea搭建tocmat
查看>>
NYOJ-626-intersection set(二分查找)
查看>>
项目管理之路(1):初步踏入项目管理
查看>>
Java 中 静态方法与非静态方法的区别
查看>>
echarts饼图显示百分比
查看>>
JMS消息
查看>>
Jenkins+ProGet+Windows Batch搭建全自动的内部包(NuGet)打包和推送及管理平台
查看>>
php上传文件及头像预览
查看>>