【笔记篇】斜率优化dp(二) SDOI2016征途

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

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

m2s2=m2mi=1(xix¯)2m=mi=1m(xix¯)2=mi=1mx2imi=1m2xix¯+mi=1mx¯2=mi=1mx2i(2i=1mxi)(mx¯)+m2(summ)2=mi=1mx2i2sum2+sum2=mi=1mx2isum2

m sum2都是常数我们可以不管, 那就是要求最小化 mi=1x2i .
所以令 f[i][j] 表示前 i 天走了前j段路, si 表示前 i 段路的前缀和, 那就能写出状态转移方程:
f[i][j]=min{f[i1][k]+(sjsk)2}(k[1,j))

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

f[j]=min{f[k]+(sjsk)2}

然后继续化成y=kx+b的形式,

f[j]=f[k]+s2j2sjsk+s2k

移项得 f[k]+s2k = 2sj sk+ f[j]s2j
这样的话我们就可以正常的斜率优化了. 最后输出 mf[n][m]sum2 就好啦~

不过要修一下边界条件.
- 比如第 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⊙)嗯

所以编辑多行laTex公式的时候会出现一个写着数字的括号是什么鬼啊.. 难道是幽灵倒计时之类的东西???

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值