Time Limit:10000MS Memory Limit:65536K Description 从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。 Input 输入的第一行为一个正整数n——树的个数(2≤n≤20000)。树从山顶到山脚按照1,2……n标号。接下来n行,每行有两个正整数(用空格分开)。第i+1行含有:wi——第i棵树的重量(公斤为单位)和 di——第i棵树和第i+1棵树之间的距离,1≤wi≤10000,0≤di≤10000。最后一个数dn,表示第n棵树到山脚的锯木厂的距离。保证所有树运到山脚的锯木厂所需要的费用小于2000000000分。 Output 输出只有一行一个数:最小的运输费用。 Sample Input
9
1 2
2 1
3 3
1 1
3 2
1 6
2 1
1 2
1 1
Sample Output
26 Source xinyue |
题目:http://mail.bashu.cn:8080/bs_oj/showproblem?problem_id=2684
数据下载:http://main.edu.pl/en/user.phtml?op=zasoby
PS:这题的题目地址不好找啊,巴蜀的地址换过一次。。。后来我写的代码一直wa,只好找数据了,原来是1L*a,并不能将 a 转成long long类型,这个错误不能再犯了
题意:给你n棵树,从山顶排到山脚,山脚下有个伐木场,你也可以在路上建两个伐木场,问将所有树砍下运到伐木场的最小费用,树只能往下运
分析:这题还是比较复杂的,一开始应该能想到枚举两个伐木场的位置,然后计算最优值,不过这样的复杂度 是O(n^2)的,肯定会超时 T_T
不过千万不能灰心,写出式子看看
f[ i ] = min { s [ n+1 , j ] +s [ j-1 , i ] + s[ i-1 , 1] } 1<=i<=j<=n+1
s[ l , r ] = w [ l ]*( d[ l ] - d[ l ]) + w[ l-1 ]* (d[ l-1 ]- d[ l ]) +.... +w[ r ] * ( d[ r ] -d [ l ])
设 sw[ i ] = sum{ w[ j ] } ( i<=j<=n ) , swd[ i ]= sum{ w[ j ] * d[ j ] } (i<=j<=n) d[ j ]与题目不同,为 j 到山脚的距离
那么经过各种YY可以得出
f[ i ] =min { - d [ j-1 ]* sw[ i ]+ d[ j-1 ]*sw[ j ] }+ sw[ 1 ]- d[ i-1 ]*(sw[ 1 ] -sw [ i ])
设 x= d[ j-1 ] , y=sw[ j ] *d[ j-1 ], a=sw[ i ]
由于后面的 sw[ 1 ]- d[ i-1 ]*(sw[ 1 ] -sw [ i ]) 只与i相关,所有不管,那么求f[ i ]转换成求函数 G=-a*x + y的最小值
转换下即y=ax + G,找到一个点使得G最小,由于斜率是固定的,那么就等价于将一条斜率为a 的直线不断往上移,直到遇到一个点,这个点便是最小值,而且可以证明这个点在直线与下凸线的切线上,由于直线的斜率a=sw [ i ]是不断增长的,那么位于这个点之前的点都不能构成新的最值,所以可以舍弃。。。。
以上我推导了两遍,因为一直wa,以为是推导错误,结果居然是判断大小的时候会超int。。。而我用1L乘之,一直wa。。。
代码:
#include<cstdio> #include<iostream> using namespace std; const int mm=22222; int d[mm],w[mm],sw[mm],swd[mm],q[mm]; int i,j,l,r,n,ans; bool TRight(int ax,int ay,int bx,int by,int cx,int cy) { return 1.0*(ax-bx)*(cy-by)>=1.0*(ay-by)*(cx-bx); } int gx(int i) { return d[i-1]; } int gy(int i) { return sw[i]*d[i-1]; } int get(int i,int a) { return gy(i)-a*gx(i); } int main() { while(~scanf("%d",&n)) { for(i=1;i<=n;++i) scanf("%d%d",&w[i],&d[i]); for(i=n-1;i>0;--i) d[i]+=d[i+1]; d[n+1]=sw[n+1]=swd[n+1]=0; for(i=n;i>0;--i) { sw[i]=sw[i+1]+w[i]; swd[i]=swd[i+1]+w[i]*d[i]; } ans=swd[1]; l=0,r=-1; for(i=n;i>0;--i) { while(l<r&&TRight(gx(q[r-1]),gy(q[r-1]),gx(q[r]),gy(q[r]),gx(i+1),gy(i+1)))--r; q[++r]=i+1; while(l<r&&get(q[l],sw[i])>=get(q[l+1],sw[i]))++l; ans=min(ans,get(q[l],sw[i])-d[i-1]*(sw[1]-sw[i])+swd[1]); } printf("%d\n",ans); } return 0; }