zoukankan      html  css  js  c++  java
  • BZOJ3675 [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)。

    正解:斜率优化

    解题报告:好鬼的题目,把样例手玩一下,发现切的顺序随便弄(一脸懵逼),那就可以从前往后DP了,然后把公式一推,发现是一个上凸壳(YWJ大佬好像用的下凸壳),然后就可以用斜率优化了。

    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <algorithm>
    #define RG register
    #define MAX(a,b) (a>b?a:b)
    #define ll long long
    const int N = 100050;
    
    using namespace std;
    
    int gi(){
        RG char ch=getchar();RG int x=0;
        while(ch<'0' || ch>'9') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    
    ll dp[N][2],f[N];
    int st[N];
    
    double cal(int k,int t,int j){
        return (double)(dp[k][j^1]-dp[t][j^1])/(f[k]-f[t]);
    }
    
    int main(){
        int n=gi(),k=gi();
        for (RG int i=1; i<=n; ++i){
            f[i]=f[i-1]+gi();
            if (f[i]==f[i-1]) --n,--i;
        }
        k=k<n?k:n-1;
        for (RG int i=1; i<=n; ++i) dp[i][1]=f[i]*(f[n]-f[i]);
        for (RG int i=2; i<=k; ++i){
            int v=i&1,c=v^1;
            int head=1,tail=1;st[1]=0;
            for (RG int j=1; j<=n; ++j){
                while(head<tail && cal(st[head+1],st[head],v)>=f[n]-f[j]) ++head;
                dp[j][v]=dp[st[head]][c]+(f[j]-f[st[head]])*(f[n]-f[j]);
                while(head<tail && cal(st[tail],j,v)>cal(st[tail],st[tail-1],v)) --tail;
                st[++tail]=j;
            }
        }
        ll ans=0;
        for (RG int i=1; i<=n; ++i) ans=MAX(ans,dp[i][k&1]);
        printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    HDU 1269 迷宫城堡
    HDU 4771 Stealing Harry Potter's Precious
    HDU 4772 Zhuge Liang's Password
    HDU 1690 Bus System
    HDU 2112 HDU Today
    HDU 1385 Minimum Transport Cost
    HDU 1596 find the safest road
    HDU 2680 Choose the best route
    HDU 2066 一个人的旅行
    AssetBundle管理机制(下)
  • 原文地址:https://www.cnblogs.com/cjk2001/p/6515710.html
Copyright © 2011-2022 走看看