[bzoj1096] [ZJOI2007]仓库建设
有n个点,每个点有p和c和坐标x,现在每个点可以选择建一座仓库,花费c块软妹币,或者运到后面的仓库,花费坐标差*p块软妹币
求最小花费 n<=1,000,000
点j连到点i的花费是(si-sj)*pj=si*pj -sj*pj
令gi=-si*pi
如果j比k优秀,那么f[j]+g[j..i]+si*p[j..i]<f[k]+g[k..i]+si*p[k..i]
(f[j]+g[j]-f[k]-g[k])/(p[j]-p[k])<s[i]
斜率优化
#include<iostream> #include<cstdio> #define ll long long #define MAXN 1000000 #define INF 200000000 #define eps 1e-8 using namespace std; 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 n,top=0,tail=1;+ ll f[MAXN+5],p[MAXN+5],c[MAXN+5],s[MAXN+5],pp[MAXN+5],g[MAXN+5]; int q[MAXN+5]; double geth(int x,int y) { return (double)(g[x]-g[y])/(double)(p[x]-p[y]-eps); } int get(int i) { while(top-tail>=1&&geth(q[tail+1],q[tail])<s[i]) tail++; return q[tail]; } void ins(int i) { while(top-tail>=1&&geth(q[top],q[top-1])>geth(i,q[top]))top--; q[++top]=i; } int main() { n=read(); for(int i=1;i<=n;i++)s[i]=read(),p[i]=read(),c[i]=read(); for(int i=1;i<=n;i++)pp[i]=pp[i-1]-p[i]*s[i],p[i]+=p[i-1]; for(int i=1;i<=n;i++) { int x=get(i); f[i]=f[x]+s[i]*(p[i-1]-p[x])+pp[i-1]-pp[x]+c[i]; f[i]=min(f[i],s[i]*(p[i-1])+pp[i-1]+c[i]); g[i]=f[i]-pp[i]; ins(i); } cout<<f[n]; return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream