• [APIO2014] 序列分割


    Description

    给定一个长度为 (n) 的序列,需要将其划分成 (k+1) 份,每次划分时会将一个段划分成两个段,本次操作的得分为划分成的两个段的和的乘积。求最大得分和为多少。

    Solution

    容易证明操作顺序对答案没有影响,具体可以证明个结合律,代数系统里面有过类似的东西。

    (f(i,j)) 表示前 (j) 个数分了 (i) 次的最大得分,则显然有转移

    [f(i,j) leftarrow f(i-1,k) + s_k (s_j-s_k) ]

    转化一下,并记 (f_j = f(i,j), g_j = f(i-1,j)),则有

    [s_k^2 - g_k = s_j s_k - f_j ]

    于是,考虑设 (Y(k) = s_k^2 - g_k , K(j) = s_j, X(k) = s_k, B(j) = -f_j),斜率优化即可,维护一个斜率单调递增的单调队列。

    自闭原因:数组大小写反,卡精度

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    #define double long double
    const int N = 100005;
    const int M = 205;
    
    int n,k,a[N],s[N],q[N],f[N],g[N],head=0,tail=0;
    int from[M][N];
    
    double Y(int k)
    {
        return s[k]*s[k]-g[k];
    }
    double X(int k)
    {
        return s[k];
    }
    double K(int j)
    {
        return s[j];
    }
    double B(double Y,double K,double X)
    {
        return Y-K*X;
    }
    
    
    
    double slope(int p,int q)
    {
        double dy=Y(p)-Y(q);
        double dx=X(p)-X(q);
        if(abs(dx)<1e-9)
        {
            return -1e32;
        }
        else 
        {
            return dy/dx;
        }
    }
    
    signed main()
    {
        // freopen("p3648.in","r",stdin);
    
        ios::sync_with_stdio(false);
    
        cin>>n>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
    
        for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    
        for(int i=1;i<=k;i++)
        {
            for(int j=1;j<=n;j++) g[j]=f[j];
            head=0;
            tail=-1;
            q[0]=0;
            for(int j=1;j<=n;j++)
            {
                while(head<tail && slope(q[head],q[head+1])<=K(j)) ++head;
                if(head<=tail)
                {
                    int k=q[head];
                    f[j]=g[k]+s[k]*(s[j]-s[k]);
                    from[i][j]=k;
                }
                else f[j]=0;
                while(head<tail && slope(q[tail-1],q[tail])>=slope(q[tail],j)) --tail;
                q[++tail]=j;
    
            }
        }
    
        cout<<f[n]<<endl;
    
        int i=k, j=from[k][n];
        while(i)
        {
            cout<<j<<" ";
            j=from[--i][j];
        }
    }
    
    
  • 相关阅读:
    ES6的Iterator,jquery Fn
    html4,xhtml,html5发展历史
    浏览器Range,Selection等选中文本对象
    高效的插入子节点DocumentFragment
    Vue 性能优化track-by
    JS中先有Object还是先有Function?
    Unicode 与(UTF-8,UTF-16,UTF-32,UCS-2)
    FormData、Blob、File、ArrayBuffer数据类型
    jQuery 2.0.3 源码分析 事件绑定
    记录:springmvc + mybatis + maven 搭建配置流程
  • 原文地址:https://www.cnblogs.com/mollnn/p/14040409.html
Copyright © 2020-2023  润新知