zoukankan      html  css  js  c++  java
  • [BZOJ 3675] 序列分割

    Link:

    BZOJ 3675 传送门

    Solution:

    首先要注意到结果与分割的顺序无关,只与最终状态有关

    实际上$res=sum_{i,jle k+1} a[i]*a[j]$

    可再转化为$res=sum_{i=1}^n a[i]*sum[i-1]$

    令$dp[i][j]$表示将前$j$个数分成$i$段的最大得分,

    $dp[i][j]=max{ dp[i−1][k]+sum[k]×(sum[j]−sum[k])}$

    可以发现这个式子明显是可以斜率优化的,且能用滚动数组,直接上就行了

    Tip:

    1、此题卡空间,不用滚动数组会$MLE$

    2、可能出现$sum[j]=sum[k]$的情况,要特判(改除法为乘法也行)

    Code:

    #include <bits/stdc++.h>
     
    using namespace std;
    typedef long long ll;
    const int MAXN=1e5+10;
    ll INF=1e18,sum[MAXN],dp[2][MAXN];
    int pre[205][MAXN],q[MAXN],n,k,x,l,r,cur=0;
     
    inline double slope(int k,int j)
    {
        if(sum[k]==sum[j]) return -INF;
        return (sum[k]*sum[k]-sum[j]*sum[j]+dp[cur^1][j]-dp[cur^1][k])*1.0/(sum[k]-sum[j]);
    }
     
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",&x),sum[i]=sum[i-1]+x;
        for(int cnt=1;cnt<=k;cnt++,cur^=1)
        {
            l=r=0;q[l]=0;
            for(int i=1;i<=n;i++)
            {
                while(l<r&&slope(q[l+1],q[l])<=sum[i]) l++;
                dp[cur][i]=dp[cur^1][q[l]]+sum[q[l]]*(sum[i]-sum[q[l]]);
                while(l<r&&slope(q[r],q[r-1])>slope(i,q[r])) r--;q[++r]=i;
            }
        }
        printf("%lld",dp[cur^1][n]);
        return 0;
    }

    Review:

    1、斜率优化中要注意除数是否可能为0

    2、感觉不少这样一边操作一边算贡献的题目最后都和中间操作无关

    多考虑一下,用分配率什么的推一推看是否只和最终态有关

    3、为了转化成符合$dp$的模型

    两两间的操作 改成 一个数与之前数(之和)的操作

  • 相关阅读:
    Python学习笔记(三)
    Python学习笔记(二)
    GDUFE ACM1159
    GDUEFE ACM1003 练手
    GDUFE ACM1033
    GDUFE ACM1128
    GDUFE ACM1002
    EDUFE ACM1050
    GDUFE ACM1007
    GDUFE ACM1003
  • 原文地址:https://www.cnblogs.com/newera/p/9304444.html
Copyright © 2011-2022 走看看