题目大意:珠宝店有许多珠宝,你需要每种珠宝各买一定的数目,各种珠宝的价格是不一样的,每种珠宝买的时候都必须多付10颗该珠宝的钱,但一种珠宝可以用比它更贵的珠宝来代替,所以有时候用更贵的珠宝来充数可能更省钱。现在问你最少要多少钱?输入数据已按珠宝按价格升序排序。
分析:开始想的时候想了一个二维的方程,但是一维就够了。设f[i]表示买了第i种珠宝,前面的珠宝都已经买了或有更贵的充数,此时所花的最少的钱。
则f[i]=min(f[k]+(sum[i]-sum[k]+10)*price[i])
设y=f[k]+sum[i]*price+10*price,x=sum[k],b=prixe[i],g=f[i],则上式变为:g=y-bx
b是递增的,所以有效决策点满足下凸包性质。
这道题我居然把一处Y(j)写成了(j),WA了许多次,真是够了。粗心害死人,一定要细心一点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define MAXN 105 6 int f[MAXN],w[MAXN],sum[MAXN],que[MAXN],head,tail,last; 7 struct zhu 8 { 9 int sum,w; 10 }arr[MAXN]; 11 int X(int i) 12 { 13 return arr[i].sum; 14 } 15 int Y(int i) 16 {return f[i]; 17 } 18 bool turnup(int i,int j,int k) 19 { 20 if((X(j)-X(k))*(long long)(Y(i)-Y(j))>(X(i)-X(j))*(long long)(Y(j)-Y(k))) 21 return 1; 22 else return 0; 23 } 24 int main() 25 { 26 int t,n; 27 scanf("%d",&t); 28 while(t--) 29 { 30 head=tail=1; 31 last=0; 32 que[tail++]=0; 33 f[0]=0; 34 arr[0].sum=0,arr[0].w=0; 35 scanf("%d",&n); 36 for(int i=1;i<=n;i++) 37 {scanf("%d %d",&arr[i].sum,&arr[i].w); 38 arr[i].sum+=arr[i-1].sum; 39 } 40 for(int i=1;i<=n;i++) 41 { 42 while(head<tail-1&&Y(que[head+1])-Y(que[head])<=arr[i].w*(long long)(X(que[head+1])-X(que[head]))) 43 head++; 44 int best=que[head]; 45 f[i]=f[best]+(arr[i].sum-arr[best].sum+10)*(long long)arr[i].w; 46 while(head<tail-1&&turnup(i,que[tail-1],que[tail-2])==0) 47 tail--; 48 que[tail++]=i; 49 } 50 printf("%d ",f[n]); 51 } 52 }