[BZOJ3156]防御准备(斜率优化dp)
2016-04-26 14:27
435 查看
题目描述
传送门题解
首先把序列反置,然后就变成了都挪向左边,第一个必须建守卫塔fi表示在i点建守卫塔的费用总和,转移方程:fi=min{fj+si−1−sj−(ci−1−cj)∗dj+costi}(j<i)其中di表示1~i的距离,ci表示1~i的点数,s表示的是d的前缀和。
注意这里第一个必须选,所以开始的队列不能为0,应该为1。并且最后一个可以不选,单独枚举。
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define LL long long const int max_n=1e6+5; const LL INF=1e9; int n,head,tail,q[max_n]; LL cost[max_n],d[max_n],s[max_n],c[max_n],f[max_n]; LL ans; inline LL K(int j){return -d[j];} inline LL B(int j){return f[j]-s[j]+c[j]*d[j];} inline LL Y(int i,int j){return K(j)*c[i-1]+B(j);} inline bool cmp(int x1,int x2,int x3){ LL w1=(K(x1)-K(x3))*(B(x2)-B(x1)); LL w2=(K(x1)-K(x2))*(B(x3)-B(x1)); return w1>=w2; } int main(){ scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%lld",&cost[i]); for (int i=1;i<=n/2;++i) swap(cost[i],cost[n-i+1]); d[1]=0; for (int i=2;i<=n;++i) d[i]=d[i-1]+1; for (int i=1;i<=n;++i) s[i]=s[i-1]+d[i]; for (int i=1;i<=n;++i) c[i]=c[i-1]+1; head=0;tail=0; q[tail]=1; f[1]=cost[1]; for (int i=2;i<=n;++i){ while (head<tail&&Y(i,q[head])>=Y(i,q[head+1])) head++; f[i]=Y(i,q[head])+s[i-1]+cost[i]; while (head<tail&&cmp(i,q[tail-1],q[tail])) tail--; q[++tail]=i; } ans=f ; for (int i=1;i<n;++i) ans=min(ans,f[i]+s -s[i]-d[i]*(c -c[i])); printf("%lld\n",ans); }
相关文章推荐
- cookie
- Java类初始化顺序
- ValueAnimator的介绍与使用
- [转]使用Memcached的8个要点
- 字符集图标制作
- sprintf、strcpy 及 memcpy 函数区别
- 均值、方差、标准差及协方差、协方差矩阵详解
- didn't meet stated Content-length,wrote:'133' bytes instead of stated '204' bytes
- 六 view controller 笔记
- XtraBackup/innobackupex 远程备份MySQL
- 数组作为函数参数
- iOS将数字转成货币格式字符串
- PHP开启opcache方法
- HDU 4195
- springIOC和DI的意义
- Tomcat服务器配置,二级域名,域名访问
- Device Tree Usage(理解DTS文件语法)
- 从android应用程序跳转到系统的各个设置页面
- Device Tree Usage(理解DTS文件语法)
- 第十二条:考虑实现Comparable接口