• 【BZOJ】【3675】【APIO2014】序列分割


    DP+斜率优化


      首先我们根据这个分割的过程可以发现:总得分等于k+1段两两的乘积的和(乘法分配律),也就是说与分割顺序是无关的。

      再对乘积进行重分组(还是乘法分配律)我们可以转化为:$ans=sum$第 i 段×前 i-1 段的和

      所以我们就可以以分割次数为阶段进行DP啦~

      令f[i][j]表示将前 j 个数分成 i 段的最大得分,那么就有$$f[i][j]=max{ f[i-1][k]+sum[k]×(sum[j]-sum[k]) }$$我们观察到这个式子其实是很像斜率优化的……而且sum明显满足单调性!所以来推一下决策单调性的式子=。=

      当决策k1<k2时:

      $$ egin{aligned} f[i-1][k1]+sum[k1]*(sum[j]-sum[k1]) &< f[i-1][k2]+sum[k2]*(sum[j]-sum[k2]) \ sum[j]*(sum[k1]-sum[k2]) &< f[i-1][k2]-f[i-1][k1]+sum[k1]^2-sum[k2]^2 \ sum[j] &> frac{f[i-1][k2]-f[i-1][k1]+sum[k1]^2-sum[k2]^2}{sum[k1]-sum[k2]} end{aligned}$$

      这题我被坑在:$sum[k1]-sum[k2]leq 0$!!!

      所以搞斜率的时候,分母可能为0……所以就不能写成斜率的形式,而是搞成上一行那种……但是由于有个负数,所以还要仔细考虑不等号的方向!QAQ

     1 /**************************************************************
     2     Problem: 3675
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:18176 ms
     7     Memory:5180 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 3675
    11 #include<vector>
    12 #include<cstdio>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 inline int getint(){
    23     int v=0,sign=1; char ch=getchar();
    24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    26     return v*sign;
    27 }
    28 const int N=1e5+10,INF=~0u>>2;
    29 typedef long long LL;
    30 /******************tamplate*********************/
    31 LL f[2][N],a[N],sum[N];
    32 int from[N],n,m,q[N];
    33 double slope(int i,int j,int k){
    34     i=i&1;
    35     return double(f[i][k]-f[i][j]+sum[j]*sum[j]-sum[k]*sum[k]);
    36 }
    37 int main(){
    38 #ifndef ONLINE_JUDGE
    39     freopen("3675.in","r",stdin);
    40     freopen("3675.out","w",stdout);
    41 #endif
    42     n=getint(); m=getint();
    43     F(i,1,n) a[i]=getint(),sum[i]=sum[i-1]+a[i];
    44     F(i,1,m){
    45         int now=i&1;
    46         int l=0,r=-1; q[0]=0;
    47         F(j,1,n){
    48             while(l<r && slope(i-1,q[l],q[l+1])>=sum[j]*(sum[q[l]]-sum[q[l+1]])) l++;
    49             int t=q[l];
    50             f[now][j]=f[now^1][t]+sum[t]*(sum[j]-sum[t]);
    51             while(l<r && slope(i-1,q[r-1],q[r])*(sum[q[r]]-sum[j])>=slope(i-1,q[r],j)*(sum[q[r-1]]-sum[q[r]])) r--;
    52             q[++r]=j;
    53         }
    54     }
    55     printf("%lld
    ",f[m&1][n]);
    56     return 0;
    57 }
    View Code

    3675: [Apio2014]序列分割

    Time Limit: 40 Sec  Memory Limit: 128 MB
    Submit: 541  Solved: 202
    [Submit][Status][Discuss]

    Description

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

    Input

    输入文件的第一行包含两个整数n和尼(k+1≤n)。
    第二行包含n个非负整数a1,n2….,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]
  • 相关阅读:
    UVa 107 The Cat in the Hat
    UVa 591 Box of Bricks
    UVa 253 Cube painting
    UVa 10161 Ant on a Chessboard
    UVa 401 Palindromes
    UVa 465 Overflow
    我不知道
    消防局的设立
    某CF的D
    保安站岗
  • 原文地址:https://www.cnblogs.com/Tunix/p/4458648.html
Copyright © 2020-2023  润新知