zoukankan      html  css  js  c++  java
  • bzoj3675【APIO2014】序列切割

    3675: [Apio2014]序列切割

    Time Limit: 40 Sec  Memory Limit: 128 MB
    Submit: 1468  Solved: 607
    [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)。




    斜率优化DP

    这里有一个结论:终于得分是仅仅和分成那些序列有关,和切割的先后顺序无关。

    (将式子稍作化简就能够证明)

    然后就能够DP了:

    f[i][j]表示到第i个数分成j组的最大得分。

    则f[i][j]=max{f[k][j-1]+sum[k]*(sum[i]-sum[k])},sum[k]是前缀和。

    发现第二维是能够省略的,状态降到一维。节省了空间。

    可是时间仍须要优化。考虑斜率优化。单调队列维护下凸包。

    详细公式的变换详见笔记本....




    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define F(i,j,n) for(int i=j;i<=n;i++)
    #define D(i,j,n) for(int i=j;i>=n;i--)
    #define ll long long
    #define maxn 100005
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    int n,m,h,t,q[maxn];
    ll sum[maxn],f[maxn],g[maxn];
    int main()
    {
    	n=read();m=read();
    	F(i,1,n) sum[i]=sum[i-1]+read();
    	while (m--)
    	{
    		F(i,1,n) g[i]=sum[i]*sum[i]-f[i];
    		h=1;t=0;
    		F(i,1,n)
    		{
    			while (h<t&&(g[q[t]]-g[q[t-1]])*(sum[i]-sum[q[t]])>=(g[i]-g[q[t]])*(sum[q[t]]-sum[q[t-1]])) t--;
    			q[++t]=i;
    			while (h<t&&g[q[h+1]]-g[q[h]]<(sum[q[h+1]]-sum[q[h]])*sum[i]) h++;
    			f[i]=sum[q[h]]*sum[i]-g[q[h]];
    		}
    	}
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    


  • 相关阅读:
    49. 字母异位词分组
    73. 矩阵置零
    Razor语法问题(foreach里面嵌套if)
    多线程问题
    Get json formatted string from web by sending HttpWebRequest and then deserialize it to get needed data
    How to execute tons of tasks parallelly with TPL method?
    How to sort the dictionary by the value field
    How to customize the console applicaton
    What is the difference for delete/truncate/drop
    How to call C/C++ sytle function from C# solution?
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7351287.html
Copyright © 2011-2022 走看看