BZOJ2726: [SDOI2012]任务安排
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2726
倒着做,前面的点对后面的点都是有贡献的。 f[i]=min(f[j]+cost[i]*(T[i]-T[j]+S)) (j>i)
然后。。。。时间可以是负数的。(所以看起来好好的单调队列+斜率优化就变成了动态凸包。。x坐标并不是有序的。。
用cdq分治处理。。
(看起来是要逆序维护下凸包的。但是我比较蠢于是把序列翻转了一下这样就变成了正着做下凸包辣。。
然后时间是负数的话,不等号的方向要改变。
(虽然我在写的时候脑子一团浆糊。。但是感觉写出来的代码还不会太乱吧。。
#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<map> #include<cmath> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 300500 #define inf int(1e9) #define ll long long using namespace std; struct data{int x,k,id;ll y; }a[maxn],s[maxn],t[maxn]; int n,S; ll f[maxn],bin[69]; int cross(data a,data b,data c){ int x1=b.x-a.x,x2=c.x-a.x; ll y1=b.y-a.y,y2=c.y-a.y; if ((x1<0)^(x2<0)) return y1*x2<=y2*x1; else return x1*y2-x2*y1<=0; } bool jud(data a,data b,int k){ ll x=b.x-a.x,y=b.y-a.y; if (x<0) return y>x*k; else return y<x*k; } int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();} return x*f; } void cdq(int l,int r){ if (l==r) { a[l].y=f[l]; return; } int l1=l,l2=(l+r)/2+1,mid=(l+r)/2; rep(i,l,r) if (a[i].id<=mid) t[l1++]=a[i]; else t[l2++]=a[i]; rep(i,l,r) a[i]=t[i]; cdq(l,mid); int top=0; rep(i,l,mid){ while (top>1&&cross(s[top-1],s[top],a[i])) top--; s[++top]=a[i]; } int j=1; rep(i,mid+1,r){ while (j<top&&jud(s[j],s[j+1],a[i].k)) j++; f[a[i].id]=min(f[a[i].id],1LL*a[i].k*(a[i].x-s[j].x+S)+f[s[j].id]); } cdq(mid+1,r); l1=l,l2=mid+1; rep(i,l,r) if (l1<=mid&&(a[l1].x<a[l2].x||l2>r)) t[i]=a[l1++]; else t[i]=a[l2++]; rep(i,l,r) a[i]=t[i]; } int main(){ n=read(); S=read(); rep(i,1,n) a[i].x=read(),a[i].k=read(); down(i,n,1) a[i].x+=a[i+1].x,a[i].k+=a[i+1].k; rep(i,1,n/2) swap(a[i],a[n-i+1]); rep(i,1,n) f[i]=1LL*a[i].k*(a[i].x+S),a[i].id=i; f[0]=0; cdq(1,n); printf("%lld\n",f[n]); return 0; }