标签:pac zjoi2007 opened 方向 一条直线 dig 决定 font spl
时间限制: 1000 ms 内存限制: 32768 KB
从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。
木材只能按照一个方向运输:朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小。假定运输每公斤木材每米需要一分钱。
输入的第一行为一个正整数n——树的个数(2≤n≤20 000)。树从山顶到山脚按照1,2……n标号。接下来n行,每行有两个正整数(用空格分开)。第i+1行含有:wi——第i棵树的重量(公斤为单位)和 di——第i棵树和第i+1棵树之间的距离,1≤wi ≤10 000,0≤di≤10 000。最后一个数dn,表示第n棵树到山脚的锯木厂的距离。保证所有树运到山脚的锯木厂所需要的费用小于2000 000 000分。
输出只有一行一个数:最小的运输费用。
9
1 2
2 1
3 3
1 1
3 2
1 6
2 1
1 2
1 1
26
数据范围玄学:n2可过,正解应该是O(n)的,所以姑且认为是106吧
sol:斜率优化dp 有点像ZJOI2007仓库建设
n2暴力几乎和上一道一样,就是稍微转化下,就把统计 j ~ i 的东西全部运到 i 需要的花费变成O(1)
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll s=0; bool f=0; char ch=‘ ‘; while(!isdigit(ch)) { f|=(ch==‘-‘); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar(‘-‘); x=-x; } if(x<10) { putchar(x+‘0‘); return; } write(x/10); putchar((x%10)+‘0‘); return; } #define W(x) write(x),putchar(‘ ‘) #define Wl(x) write(x),putchar(‘\n‘) const int N=200005; const ll inf=0x7fffffffffff; int n; ll W[N],W_Qzh[N],Dis[N],Cost[N]; ll dp_Last[N],dp[N]; int main() { int i,j; R(n); Dis[1]=0; for(i=1;i<=n;i++) { W[i]=read(); W_Qzh[i]=W_Qzh[i-1]+W[i]; Dis[i+1]=Dis[i]+read(); Cost[i]=Cost[i-1]+W[i]*Dis[i]; } for(i=1;i<=n;i++) { dp_Last[i]=Dis[i]*W_Qzh[i]-Cost[i]; } memset(dp,63,sizeof dp); for(i=2;i<=n;i++) { for(j=1;j<i;j++) { dp[i]=min(dp[i],dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j])); } } ll ans=inf; for(i=2;i<=n;i++) { ans=min(ans,dp[i]+Dis[n+1]*(W_Qzh[n]-W_Qzh[i])-(Cost[n]-Cost[i])); } Wl(ans); return 0; } /* input 9 1 2 2 1 3 3 1 1 3 2 1 6 2 1 1 2 1 1 output 26 */
推导如下
j<k<i
--> dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j])
--> dp_Last[j]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[j]-Cost[i]+Cost[j] (S2)
--> dp_Last[k]+Dis[i]*(W_Qzh[i]-W_Qzh[k])-(Cost[i]-Cost[k])
--> dp_Last[k]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[k]-Cost[i]+Cost[k] (S1)
若k比j优 则 S1<=S2
dp_Last[k]-Dis[i]*W_Qzh[k]+Cost[k] <= dp_Last[j]-Dis[i]*W_Qzh[j]+Cost[j]
(dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]) <= Dis[i]*(W_Qzh[k]-W_Qzh[j])
/* j<k<i --> dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j]) --> dp_Last[j]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[j]-Cost[i]+Cost[j] (S2) --> dp_Last[k]+Dis[i]*(W_Qzh[i]-W_Qzh[k])-(Cost[i]-Cost[k]) --> dp_Last[k]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[k]-Cost[i]+Cost[k] (S1) 若k比j优 则 S1<=S2 dp_Last[k]-Dis[i]*W_Qzh[k]+Cost[k] <= dp_Last[j]-Dis[i]*W_Qzh[j]+Cost[j] (dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]) <= Dis[i]*(W_Qzh[k]-W_Qzh[j]) */ #include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll s=0; bool f=0; char ch=‘ ‘; while(!isdigit(ch)) { f|=(ch==‘-‘); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar(‘-‘); x=-x; } if(x<10) { putchar(x+‘0‘); return; } write(x/10); putchar((x%10)+‘0‘); return; } #define W(x) write(x),putchar(‘ ‘) #define Wl(x) write(x),putchar(‘\n‘) const int N=200005; const ll inf=0x7fffffffffff; int n; ll W[N],W_Qzh[N],Dis[N],Cost[N]; ll dp_Last[N],dp[N],Que[N]; //(dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]) <= Dis[i]*(W_Qzh[k]-W_Qzh[j]) inline bool Panduan(int j,int k,int i) //j<k<i { ll S1=(dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]); ll S2=Dis[i]*(W_Qzh[k]-W_Qzh[j]); return (S1<=S2)?(1):(0); } inline bool Panduan_Rev(int j,int k,int i) //j<k<i { ll S1=((dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]))*(W_Qzh[i]-W_Qzh[k]); ll S2=((dp_Last[i]+Cost[i])-(dp_Last[k]+Cost[k]))*(W_Qzh[k]-W_Qzh[j]); return (S1>=S2)?(1):(0); } int main() { int i,j; R(n); Dis[1]=0; for(i=1;i<=n;i++) { W[i]=read(); W_Qzh[i]=W_Qzh[i-1]+W[i]; Dis[i+1]=Dis[i]+read(); Cost[i]=Cost[i-1]+W[i]*Dis[i]; } for(i=1;i<=n;i++) { dp_Last[i]=Dis[i]*W_Qzh[i]-Cost[i]; } int Head=1,Tail=1; Que[1]=0; for(i=1;i<=n;i++) { while(Head<Tail&&Panduan(Que[Head],Que[Head+1],i)) Head++; j=Que[Head]; dp[i]=dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j]); while(Head<Tail&&Panduan_Rev(Que[Tail-1],Que[Tail],i)) Tail--; Que[++Tail]=i; } ll ans=inf; for(i=2;i<=n;i++) { ans=min(ans,dp[i]+Dis[n+1]*(W_Qzh[n]-W_Qzh[i])-(Cost[n]-Cost[i])); } Wl(ans); return 0; } /* input 9 1 2 2 1 3 3 1 1 3 2 1 6 2 1 1 2 1 1 output 26 */
标签:pac zjoi2007 opened 方向 一条直线 dig 决定 font spl
原文地址:https://www.cnblogs.com/gaojunonly1/p/10421086.html