bzoj3675&UOJ104 [Apio2014]序列分割

网友投稿 856 2022-08-29

bzoj3675&UOJ104 [Apio2014]序列分割

bzoj3675&UOJ104 [Apio2014]序列分割

​​‎ 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)。 可以通过观察得到 当我们确定好切刀位置之后我们的分数就和我们切刀的顺序就无关了 那么我们可以考虑 我每次一层一层做(模拟切刀 然后 做k次即可 假设现在已经切了k-1次 那么我们获得一个dp1[i]代表 1~i切k-1刀的最大值是多少 那么我可以利用dp1来求dp数组 怎么求 我每次都是枚举一下前面的位置 然后假设前面就分好了 然后后面再另分为一段 即dp1[j]然后另一段j~i 写出朴素dp方程之后可以发现这是个斜率优化的方程 并且斜率满足递增 那么我们就可以用单调队列来维护 那么我们可以设j1< j2 什么时候j1不比j2优 dp1[j1]−dp1[j2]+sum[j2]2−sum[j1]2sum[j2]−sum[j1]

#include#include#define ll long long#define N 110000using namespace std;inline char gc(){ static char now[1<<16],*S,*T; if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;} return *S++; }inline int read(){ int x=0,f=1;char ch=gc(); while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();} while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc(); return x*f;}ll dp[2][N],sum[N];int n,k,q[N],pre,now,from[220][110000];inline double slope(int j1,int j2){ if (sum[j1]==sum[j2]) return -1e18; return (double)(dp[pre][j1]-dp[pre][j2]+sum[j2]*sum[j2]-sum[j1]*sum[j1])/(sum[j2]-sum[j1]);}int main(){ freopen("bzoj3675.in","r",stdin); n=read();k=read();pre=0,now=1; for (int i=1;i<=n;++i) sum[i]=sum[i-1]+read(); for (int j=1;j<=k;++j){ int l=1,r=0;q[++r]=0; for (int i=1;i<=n;++i){ while(l=slope(q[r],i)) --r;q[++r]=i; } pre^=1;now^=1; }printf("%lld\n",dp[pre][n]);int now=n; for (int i=k;i;--i){ now=from[i][now];printf("%d,now); } return 0;}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:bzoj3831 [Poi2014]Little Bird
下一篇:多进程和多线程的优缺点(关于多线程的优缺点)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~