其他分享
首页 > 其他分享> > [APIO 2014] 序列分割

[APIO 2014] 序列分割

作者:互联网

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=3675

[算法]

         首先 , 我们发现将一段序列切成若干段所获得的收益与顺序无关

         于是我们可以用fi,j表示切i次 , 前j个数的最大收益

         令sumi表示ai的前缀和

         显然 , fi,j = max{ fi-1,k + sumk * (sumj - sumk) }

         斜率优化即可

         此题内存限制较紧 , 可以使用滚动数组优化空间复杂度

         时间复杂度 : O(NK)

[代码]

       

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXK 210
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;

int n , k , l , r;
ll X[MAXN] , Y[MAXN] , sum[MAXN] , f[2][MAXN];
int a[MAXN] , q[MAXN] , last[MAXK][MAXN];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
int main()
{
        
        read(n); read(k);
        for (int i = 1; i <= n; i++)
        {
                read(a[i]);
                sum[i] = sum[i - 1] + a[i];
        }
        for (int i = 1; i <= k; i++)
        {
                int now = i & 1 , pre = now ^ 1;
                f[now][q[l = r = 1] = 0] = 0;
                for (int j = 1; j <= n; j++)
                {
                        while (l < r && Y[q[l + 1]] - Y[q[l]] >= -sum[j] * (X[q[l + 1]] - X[q[l]])) ++l;
                        f[now][j] = Y[q[l]] + X[q[l]] * sum[j];
                        X[j] = sum[j];
                        Y[j] = f[pre][j] - sum[j] * sum[j];
                        last[i][j] = q[l];
                        while (l < r && (Y[j] - Y[q[r]]) * (X[q[r]] - X[q[r - 1]]) >= (Y[q[r]] - Y[q[r - 1]]) * (X[j] - X[q[r]])) --r;
                        q[++r] = j; 
                }        
        }
        printf("%lld\n" , f[k & 1][n]);
        int now = n , s = k;
        vector< int > ans;
        while (now > 0)
        {
                now = last[s][now];
                if (now) ans.push_back(now);
                --s;
        }
        reverse(ans.begin() , ans.end());
    
        // 输出方案...

        return 0;
    
}

 

标签:APIO,int,sum,long,MAXN,ans,序列,2014,now
来源: https://www.cnblogs.com/evenbao/p/10354216.html