[BZOJ2726][SDOI2012]任务安排(斜率优化dp+cdq分治)
来源:互联网 发布:淘宝的全球购在哪 编辑:程序博客网 时间:2024/05/17 02:33
题目描述
传送门
题解
哈哈哈速度实力倒数第一
也不知为什么写的奇慢无比卡常数卡到丧心病狂才勉强过了
我分明是把sort都搞成归并了呀…
这题是dp+cdq分治好题啊
首先考虑最裸的dp怎么搞
f(i)表示前i个搞完的最小花费…
等等,时间有后效性…记录一下时间?
瞬间爆炸
实际上我们可以发现,只要知道一共划分成了几部分,就能通过T的前缀和以及s计算出时间,所以令f(i,j)表示划分成i段,划分到第j个,最小花费
f(i,j)=min{f(i-1,k)+(sT(j)+s*i)*(sF(j)-sF(k))}(0<=k<=j-1)其中sF和sT分别表示F和T的前缀和
但是这样复杂度是
然后再考虑稍微不裸一点的dp怎么搞
f(i)表示前i个搞完的最小花费…
不是说了时间有后效性嘛…可是必须得是一维dp不能是二维的啊…所以这里就需要机智一下了
假设我们将整个序列划分成了m段,每一段的F的和依次是p1,p2..pm,每一段结束的时间(不算s)分别是t1,t2…tm,那么实际上这种划分方式的花费就是(s+t1)*p1+(2*s+t2)*p2+…+(m*s+tm)*pm
将这个式子拆开s*p1+2*s*p2+…+m*s*pm+t1*p1+t2*p2+…+tm*pm=s*(p1+2*p2+3*p3+…+m*pm)+t1*p1+t2*p2+…+tm*pm
观察前面的那个式子,系数是等差的,其实稍微转化一下就是另一种形式:(p1+p2+p3+…+pm)+(p2+p3+…+pm)+(p3+…+pm)+…+(pm)
其实就是F的后缀和!
这样的话,我们就非常完美地将s所带来的影响消除了,状态转移方程就可以写为:f(i)=max{f(j)+sT(i)*sF(j+1)+s*sF(j+1)}(0<=j<=i-1),其中sT(i)表示T的前缀和,sF(i)表示F的后缀和
时间复杂度
md如果这题时间没有负数不就是一个裸斜率优化嘛…
但是出题人说:“对时间的理解不要那么狭隘嘛”
于是一掌把我打回cdq分治
下面就是斜率优化+cdq分治的常规套路了
f(i)=f(j)+sT(i)*sF(j+1)+s*sF(j+1),令y(j)=f(j)+s*sF(j+1),x(j)=sF(j+1)
那么f(i)=sT(i)*x(j)+y(j),y(j)=-sT(i)*x(j)+f(i)
这样就可以看成是一条斜率为-sT(i),截距为f(i)的直线,要使f(i)最小,实际上就是要选择一个点使直线的纵截距最小
显然可能成为答案的点都在一个下凸壳上,我们可以选择用splay维护凸包然后每一次二分,或者写(bu)好写(bu)好调(tle)的cdq分治
代码
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define LL long long#define N 1005int n;LL s,ans,T[N],F[N],sT[N],sF[N],f[N][N],g[N];int main(){ scanf("%d%d",&n,&s); for (int i=1;i<=n;++i) scanf("%I64d%I64d",&T[i],&F[i]); for (int i=1;i<=n;++i) sT[i]=sT[i-1]+T[i],sF[i]=sF[i-1]+F[i]; memset(f,127,sizeof(f));ans=f[0][0];f[0][0]=0; for (int i=1;i<=n;++i) for (int j=i;j<=n;++j) { for (int k=0;k<j;++k) f[i][j]=min(f[i][j],f[i-1][k]+(sT[j]+s*(LL)i)*(sF[j]-sF[k])); } for (int i=1;i<=n;++i) for (int j=1;j<=i;++j) g[i]=min(g[i],f[j][i]); for (int i=1;i<=n;++i) printf("%d : %I64d\n",i,g[i]); printf("%I64d\n",g[n]);}
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define LL long long#define N 300005int n;LL s,T[N],F[N],sT[N],sF[N],f[N];int d[N];int main(){ scanf("%d%d",&n,&s); for (int i=1;i<=n;++i) scanf("%I64d%I64d",&T[i],&F[i]); for (int i=1;i<=n;++i) sT[i]=sT[i-1]+T[i]; for (int i=n;i>=0;--i) sF[i]=sF[i+1]+F[i]; memset(f,127,sizeof(f));f[0]=0; for (int i=1;i<=n;++i) { for (int j=0;j<i;++j) if (f[j]+sT[i]*sF[j+1]+s*sF[j+1]<f[i]) f[i]=f[j]+sT[i]*sF[j+1]+s*sF[j+1]; f[i]-=sT[i]*sF[i+1]; } printf("%I64d\n",f[n]);}
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 300005#define LL long longconst int inf=1e9;int n,s,T[N],F[N],sT[N],sF[N];LL f[N];struct data{int k,x;LL y;int id;}q[N],p[N],nq[N],np[N];int stack[N];int read(){ int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f;}int cmpx(data a,data b){ return a.x<b.x||(a.x==b.x&&a.y>b.y);}int cmpk(data a,data b){ return a.k<b.k;}double getk(data a,data b){ if (a.x==b.x) return -inf; double ax=(double)a.x,ay=(double)a.y,bx=(double)b.x,by=(double)b.y; return (ay-by)/(ax-bx);}inline void cdq(int l,int r){ if (l==r) { f[l]-=(LL)sT[l]*sF[l+1]; q[l].y=f[l]+(LL)s*sF[l+1]; p[l].y=f[l]+(LL)s*sF[l+1]; return; } int mid=(l+r)>>1; int ql=l,qr=mid+1,pl=l,pr=mid+1; for (int i=l;i<=r;++i) { if (q[i].id<=mid) nq[ql++]=q[i]; else nq[qr++]=q[i]; if (p[i].id<=mid) np[pl++]=p[i]; else np[pr++]=p[i]; } for (int i=l;i<=r;++i) q[i]=nq[i],p[i]=np[i]; cdq(l,mid); int top=0; for (int i=l;i<=mid;++i) { while (top>1&&getk(q[i],q[stack[top]])<=getk(q[stack[top-1]],q[stack[top]])) --top; stack[++top]=i; } int now=1; for (int i=mid+1;i<=r;++i) { while (now<top&&getk(q[stack[now]],q[stack[now+1]])<=p[i].k) ++now; int r=stack[now],t=p[i].id; LL Min=(LL)q[r].x*sT[t]+q[r].y; if (Min<f[t]) f[t]=Min; } cdq(mid+1,r); pl=l,pr=mid+1,now=l; while (pl<=mid&&pr<=r) { if (q[pl].x<q[pr].x) nq[now++]=q[pl++]; else nq[now++]=q[pr++]; } while (pl<=mid) nq[now++]=q[pl++]; while (pr<=r) nq[now++]=q[pr++]; pl=l,pr=mid+1,now=l; while (pl<=mid&&pr<=r) { if (p[pl].k<p[pr].k) np[now++]=p[pl++]; else np[now++]=p[pr++]; } while (pl<=mid) np[now++]=p[pl++]; while (pr<=r) np[now++]=p[pr++]; for (int i=l;i<=r;++i) q[i]=nq[i],p[i]=np[i];}int main(){ n=read();s=read(); for (int i=1;i<=n;++i) T[i]=read(),F[i]=read(); for (int i=n;i>=0;--i) sF[i]=sF[i+1]+F[i]; for (int i=0;i<=n;++i) { if (i) sT[i]=sT[i-1]+T[i]; q[i].id=i,q[i].k=-sT[i],q[i].x=sF[i+1]; p[i]=q[i]; } sort(q+1,q+n+1,cmpx); sort(p+1,p+n+1,cmpk); memset(f,127,sizeof(f));f[0]=0; cdq(0,n); printf("%lld\n",f[n]);}
- [BZOJ2726][SDOI2012]任务安排(斜率优化dp+cdq分治)
- BZOJ2726 [SDOI2012]任务安排
- 【SDOI2012】bzoj2726 任务安排
- 【bzoj2726】[SDOI2012]任务安排
- bzoj 2726 [SDOI2012]任务安排 CDQ分治维护凸包 dp
- [BZOJ3963][WF2011]MachineWorks(斜率优化dp+cdq分治)
- BZOJ 1492 斜率优化dp && cdq分治
- bzoj1492 [ NOI2007 ] --斜率优化DP+cdq分治
- [BZOJ3672][NOI2014]购票-点分治-CDQ分治-斜率优化DP
- CDQ分治与斜率优化DP——学习笔记
- [BZOJ3963][WF2011][CDQ分治][斜率优化][DP]MachineWorks
- [BZOJ1492][NOI2007][CDQ分治][斜率优化][DP]货币兑换Cash
- [BZOJ 3963][WF2011]MachineWorks:CDQ分治|DP斜率优化
- 【NOI2007T2】货币兑换-DP斜率优化+CDQ分治
- [BZOJ1492][NOI2007]货币兑换Cash-斜率优化DP-CDQ分治
- bzoj3672 [ NOI2014 ] -- 树上CDQ分治 + 斜率优化DP
- [BZOJ1492][NOI2007]货币兑换Cash(斜率优化dp+cdq分治)
- BZOJ1492:[NOI2007]货币兑换Cash (CDQ分治+斜率优化DP/平衡树维护凸壳)
- 算法思想:关于找数组中第K大的数的思考
- Intent介绍及使用方法
- 上位机
- 如何用java调用网站的API,获得json文件,并且简单解析它?
- 一位过来人的经验
- [BZOJ2726][SDOI2012]任务安排(斜率优化dp+cdq分治)
- Error creating bean with name
- Java 多态实例代码
- 最全面的HTTP知识总结
- 【APIO2012T1】派遣-贪心+左偏树
- Java学习笔记170326
- Minecraft poj
- sanji
- Groovy的语法入门