• 洛谷P4072 [SDOI2016]征途(斜率优化)


    传送门

    推式子(快哭了……)$$s^2*m^2=sum _{i=1}^m (x_i-ar{x})^2$$

    $$s^2*m^2=m*sum _{i=1}^m x_i^2-2*sum_nsum _{i=1}^m x_i+sum_n^2$$

    $$s^2*m^2=m*sum _{i=1}^m x_i^2+(sum_n-sum _{i=1}^m x_i)^2-(sum _{i=1}^m x_i)^2$$

    然后因为$sum_n$和$sum _{i=1}^m x_i$两项是定值,且值相等,所以$$s^2*m^2=m*sum _{i=1}^m x_i^2-(sum _{i=1}^m x_i)^2$$

    我们发现$(sum _{i=1}^m x_i)^2$是一个定值,那么我们的目的就是让$sum _{i=1}^m x_i^2$最小

    总算扯到dp上了不容易啊……

    我们设$dp[i][l]$表示前$i$条路$l$天走,最小的sum _{a=1}^i x_a^2是多少,那么有如下的状态转移方程$$dp[i][l]=min{dp[j][l-1]+(sum[i]-sum[j])^2}$$

    然后考虑斜率优化(以下省略$l$这一维)

    假设$j$比$k$更优,则有$$dp[j]+(sum[i]-sum[j])^2<dp[k]+(sum[i]-sum[k])^2$$

    展开,移项$$dp[j]+sum[j]^2-dp[k]-sum[k]^2<2*sum[i]*sum[j]-2*sum[i]*sum[k]$$

    $$frac{dp[j]+sum[j]^2-dp[k]-sum[k]^2}{sum[j]-sum[k]}<2*sum[i]$$

    然后就可以上斜率优化了

    ps:注意当$l$为$0$的时候dp要都初始化为$sum[i]^2$

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #define ll long long
     5 using namespace std;
     6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     7 char buf[1<<21],*p1=buf,*p2=buf;
     8 inline int read(){
     9     #define num ch-'0'
    10     char ch;bool flag=0;int res;
    11     while(!isdigit(ch=getc()))
    12     (ch=='-')&&(flag=true);
    13     for(res=num;isdigit(ch=getc());res=res*10+num);
    14     (flag)&&(res=-res);
    15     #undef num
    16     return res;
    17 }
    18 const int N=3005;
    19 ll sum[N],sp[N],dp[N];int n,m,h,t,q[N],r;
    20 inline ll Y(int i){return sp[i]+sum[i]*sum[i];}
    21 inline double slope(int j,int k){
    22     return (Y(j)-Y(k))*1.0/(sum[j]-sum[k]);
    23 }
    24 int main(){
    25     //freopen("testdata.in","r",stdin);
    26     n=read(),m=read();
    27     for(int i=1;i<=n;++i)
    28     sum[i]=read()+sum[i-1],sp[i]=sum[i]*sum[i];
    29     for(int a=1;a<m;++a){
    30         h=t=0;q[0]=a;
    31         for(int i=a+1;i<=n;++i){
    32             while(h<t&&slope(q[h],q[h+1])<2*sum[i]) ++h;
    33             dp[i]=sp[q[h]]+(sum[i]-sum[q[h]])*(sum[i]-sum[q[h]]);
    34             while(h<t&&slope(q[t],q[t-1])>slope(q[t-1],i)) --t;q[++t]=i;
    35         }
    36         for(int i=1;i<=n;++i) sp[i]=dp[i];
    37     }
    38     printf("%lld
    ",-sum[n]*sum[n]+m*dp[n]);
    39     return 0;
    40 }
  • 相关阅读:
    论分治与归并思想
    关于缩短cin时间的方法
    【lower_bound、upperbound讲解、二分查找、最长上升子序列(LIS)模版】
    getDomain(url)-我的JavaScript函数库-mazey.js
    jQuery-PHP跨域请求数据
    ASP-Server.Transfer-Response.Redirect
    jQuery获取相邻标签的值
    分界线<hr/>
    jQuery获取input复选框的值
    Bootstrap支持的JavaScript插件
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9547048.html
Copyright © 2020-2023  润新知