zoukankan      html  css  js  c++  java
  • 【笔记篇】斜率优化dp(二) SDOI2016征途

    =传=送=门=
    搜题目名会搜出很多奇怪的东西... 这个题目似乎有点毒?
    比如在bzoj和loj上可以1A的代码上会在luogu TLE 2个点, 在cogs TLE 10个点 但是根据已有的资料来看数据都是一样的...毒瘤评测姬毁我OI!!!
    这个题的状态转移方程并不是很好推的说. 出题人让(*m^2)肯定是有目的的啊..
    (比如不让乘(m^2)我们可能会需要考虑乘(m^2)最后再除掉之类的)

    然后就化一波式子: 我们令(sum)表示(n)段路的总和.

    [m^2s^2=m^2frac{sum_{i=1}^m(x_i-ar x)^2}m=msum_{i=1}^m(x_i-ar x)^2\=msum_{i=1}^mx_i^2-msum_{i=1}^m2x_iar x+msum_{i=1}^mar x^2\ =msum_{i=1}^mx_i^2-(2sum_{i=1}^mx_i)*(m*ar x)+m^2(frac{sum}m)^2\=msum_{i=1}^mx_i^2-2sum^2+sum^2=msum_{i=1}^mx_i^2-sum^2 ]

    (m)(sum^2)都是常数我们可以不管, 那就是要求最小化(sum_{i=1}^mx_i^2).
    所以令(f[i][j])表示前(i)天走了前(j)段路, (s_i)表示前(i)段路的前缀和, 那就能写出状态转移方程:

    [f[i][j]=min{f[i-1][k]+(s_j-s_k)^2} (kin[1,j)) ]

    那很明显这个是(O(n^3))可以做的, 这样能拿到60pts了就.
    但是想A的话 很明显要采用一种(o(n^2))的算法. 当然你要能(O(n))甚至(O(1))过也没啥问题...
    那我们就要搬出斜率优化了. 我们继续化式子.
    首先很明显第一维跟后面这一堆没啥关系, 那就不优化了, 也可以把这一维去掉, 到时候一滚动数组(其实不滚也能过)就行了.
    那状态转移方程就可以改写成:

    [f[j]=min{f'[k]+(s_j-s_k)^2} ]

    然后继续化成y=kx+b的形式, $$f[j]=f'[k]+s_j2-2s_js_k+s_k2$$
    移项得(f'[k]+s_k^2)=(2s_j)(s_k+)(f[j]-s_j^2)
    这样的话我们就可以正常的斜率优化了. 最后输出(m*f[n][m]-sum^2)就好啦~

    不过要修一下边界条件.

    • 比如第(i)天完全可以从(i)开始找, 总不可能回去找前面的路(这样也不会出现被0除错误),
    • 然后(f[1][x])显然应该等于(s[x]^2), 这样就可以了.
    • 然后又是要开long long的题整天开long long还是挺烦的, 什么时候普及64位系统啊= =

    然后就是代码: 并不知道究竟能不能AC 请谨慎复制!

    #include <cstdio>
    #include <cstring>
    const int N=3030;typedef long long LL;
    LL s[N],q[N],n,m,h,t;LL f[N],g[N];
    inline LL gn(LL a=0,char c=0){
        for(;c<'0'||c>'9';c=getchar());
        for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
    }
    inline double slope(LL x,LL y){return 1.0*(g[x]+s[x]*s[x]-g[y]-s[y]*s[y])/(s[x]-s[y]);}
    int main(){ n=gn(); m=gn();
        for(LL i=1;i<=n;++i) s[i]=s[i-1]+gn(),g[i]=s[i]*s[i];
        for(LL i=2;i<=m;++i){h=0; t=0; q[h]=i-1;
            for(LL j=i;j<=n;++j){    
                while(h<t&&slope(q[h],q[h+1])<2*s[j]) ++h;
                f[j]=g[q[h]]+(s[j]-s[q[h]])*(s[j]-s[q[h]]);
                while(h<t&&slope(q[t],q[t-1])>slope(j,q[t])) --t;
                q[++t]=j;
            }::memcpy(g,f,sizeof(g));
        }printf("%lld",f[n]*m-s[n]*s[n]);
    }
    

    被莫名的非主观因素的TLE卡掉好多下午的学(tui)(fei)时间, 心情并不怎么好...
    不过下雪了出去玩了一圈就非常爽了~ (⊙v⊙)嗯

  • 相关阅读:
    准备 LVM Volume Provider
    掌握 cinder-scheduler 调度逻辑
    Cinder 组件详解
    掌握 Cinder 的设计思想
    理解 Cinder 架构
    1 张图秒懂 Nova 16 种操作
    计算节点宕机了怎么办?- 每天5分钟玩转 OpenStack(43)
    Live Migrate 操作
    Resize Instance 操作详解
    关于Linux的10个核心面试问题与答案
  • 原文地址:https://www.cnblogs.com/enzymii/p/8413692.html
Copyright © 2011-2022 走看看