[CEOI2004]锯木厂选址
试题分析
做这种题就应该去先写个暴力代码
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=200011; int w[N],n,f[N],deep[N],sum,s[N],p[N],k[N]; int calc(int l,int r){ return (p[r]-p[l-1])-deep[r]*(k[r]-k[l-1]); } int main(){ // freopen("5.in","r",stdin); memset(f,127/3,sizeof(f));f[0]=0; n=read(); for(int i=1;i<=n;i++) w[i]=read(),deep[i]=read(); for(int i=n;i>=1;i--) deep[i]+=deep[i+1]; n++; for(int i=1;i<=n;i++) s[i]=w[i]*deep[i]; for(int i=1;i<=n;i++) p[i]=p[i-1]+s[i]; for(int i=1;i<=n;i++) k[i]=k[i-1]+w[i]; for(int i=1;i<=n;i++){ for(int j=0;j<i;j++){ f[i]=min(f[i],-deep[j]*k[j]-deep[i]*k[i]+deep[i]*k[j]+deep[n]*k[i]); } } int maxn=INT_MAX; for(int i=1;i<=n;i++) maxn=min(maxn,f[i]);cout<<maxn-deep[n]*k[n]+p[n]; }
然后再把calc放在里面,把无用的东西提出去。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=200011; int w[N],n,f[N],deep[N],sum,s[N],p[N],k[N]; int calc(int l,int r){ return (p[r]-p[l-1])-deep[r]*(k[r]-k[l-1]); } int main(){ // freopen("5.in","r",stdin); memset(f,127/3,sizeof(f));f[0]=0; n=read(); for(int i=1;i<=n;i++) w[i]=read(),deep[i]=read(); for(int i=n;i>=1;i--) deep[i]+=deep[i+1]; n++; for(int i=1;i<=n;i++) s[i]=w[i]*deep[i]; for(int i=1;i<=n;i++) p[i]=p[i-1]+s[i]; for(int i=1;i<=n;i++) k[i]=k[i-1]+w[i]; for(int i=1;i<=n;i++){ for(int j=0;j<i;j++){ f[i]=min(f[i],-deep[j]*k[j]+deep[i]*k[j]); } } int maxn=INT_MAX; for(int i=1;i<=n;i++) maxn=min(maxn,f[i]-deep[i]*k[i]+deep[n]*k[i]);cout<<maxn-deep[n]*k[n]+p[n]; }
然后再斜率优化一下,因为我维护的是最大值,所以维护一个上凸壳即可
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #define int long long using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=200011; int w[N],n,f[N],deep[N],sum,s[N],p[N],k[N],l,r,que[N],X[N],Y[N],minn=LLONG_MAX; signed main(){ // freopen("5.in","r",stdin); memset(f,127/3,sizeof(f));f[0]=0; n=read(); for(int i=1;i<=n;i++) w[i]=read(),deep[i]=read(); for(int i=n;i>=1;i--) deep[i]+=deep[i+1]; n++; for(int i=1;i<=n;i++) s[i]=w[i]*deep[i]; for(int i=1;i<=n;i++) p[i]=p[i-1]+s[i]; for(int i=1;i<=n;i++) k[i]=k[i-1]+w[i]; l=r=1,que[1]=0;Y[0]=deep[0]*k[0],X[0]=k[0]; for(int i=1;i<=n;i++){ while(l<r&&Y[que[l+1]]-Y[que[l]]>=deep[i]*(X[que[l+1]]-X[que[l]])) l++; f[i]=deep[i]*k[que[l]]-deep[que[l]]*k[que[l]]; X[i]=k[i],Y[i]=deep[i]*k[i]; while(l<r&&(Y[que[r]]-Y[que[r-1]])*(X[i]-X[que[r]])<=(X[que[r]]-X[que[r-1]])*(Y[i]-Y[que[r]])) r--; que[++r]=i; } for(int i=1;i<=n;i++) minn=min(minn,f[i]-deep[i]*k[i]+deep[n]*k[i]);printf("%lld\n",minn-deep[n]*k[n]+p[n]); return 0; }