zoukankan      html  css  js  c++  java
  • 【bzoj3675】[Apio2014]序列分割 斜率优化dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6835179.html


    题目描述

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

    输入

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

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

    输出

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

    样例输入

    7 3
    4 1 3 4 0 2 3

    样例输出

    108


    题解

    斜率优化dp

    首先可以证得分割的顺序对答案没有影响。

    设连续的3部分之和分别为a、b、c,则先分割ab再分割bc的分数为a*(b+c)+b*c=a*b+a*c+b*c,先分割bc再分割ab的分数为(a+b)*c+a*b=a*b+a*c+b*c,它们完全相同。

    这样我们就可以从左到右按顺序依次分割。

    设f[i][p]表示前i个数分割p次的最大分数,那么有f[i][p]=f[j][p-1]+(sum[i]-sum[j])*sum[j]

    这样时间复杂度为O(n^2*p),会TLE,需要优化。

    将dp方程变形,得sum[j]*sum[j]-f[j][p-1]=sum[i]*sum[j]-f[i][p],

    这样可以斜率优化来解决,此时y=sum[j]*sum[j]-f[j][p-1],k=sum[i],x=sum[j],均为正数(其实是故意这样移项的)。

    然后要求的是f[i][p]的最大值,即-f[i][p]的最小值,所以应该维护一个上凸包。

    另外需要开long long导致MLE,所以需要滚动数组。

    #include <cstdio>
    #define y(i , d) (sum[i] * sum[i] - f[i][d])
    typedef long long ll;
    ll sum[100010] , f[100010][2];
    int q[100010];
    int main()
    {
    	int n , k , i , j , l , r , d = 0;
    	scanf("%d%d" , &n , &k);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &sum[i]) , sum[i] += sum[i - 1];
    	for(j = 1 ; j <= k ; j ++ )
    	{
    		l = r = 0 , d ^= 1;
    		for(i = 1 ; i <= n ; i ++ )
    		{
    			while(l < r && y(q[l + 1] , d ^ 1) - y(q[l] , d ^ 1) <= sum[i] * (sum[q[l + 1]] - sum[q[l]])) l ++ ;
    			f[i][d] = f[q[l]][d ^ 1] + (sum[i] - sum[q[l]]) * sum[q[l]];
    			while(l < r && (y(i , d ^ 1) - y(q[r] , d ^ 1)) * (sum[q[r]] - sum[q[r - 1]]) <= (y(q[r] , d ^ 1) - y(q[r - 1] , d ^ 1)) * (sum[i] - sum[q[r]])) r -- ;
    			q[++r] = i;
    		}
    	}
    	printf("%lld
    " , f[n][k & 1]);
    	return 0;
    }

     

  • 相关阅读:
    CodeForces 347B Fixed Points (水题)
    CodeForces 347A Difference Row (水题)
    CodeForces 346A Alice and Bob (数学最大公约数)
    CodeForces 474C Captain Marmot (数学,旋转,暴力)
    CodeForces 474B Worms (水题,二分)
    CodeForces 474A Keyboard (水题)
    压力测试学习(一)
    算法学习(一)五个常用算法概念了解
    C#语言规范
    异常System.Threading.Thread.AbortInternal
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6835179.html
Copyright © 2011-2022 走看看