题意:给你n个物品的数量和价格,单个购买物品时数量加10(买一个花11个钱),连续购买多个时,数量总和加10,以结束物品单价为准(价格是单价递增的,是以最贵的计算,所以就是最后一个物品),求最小单价
思路:就是简单的n2dp,注意初始化为0x3f,而不是0,还有就是在选取第j个物品时要从0开始,这样可以少写一个从0转移单个的直接赋值的语句,斜率优化下次再更新
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=105; int a[maxn],val[maxn],dp[maxn],pre[maxn]; int main() { int T; scanf("%d",&T); while(T--){ int n; memset(dp,0x3f,sizeof(dp)); scanf("%d",&n); pre[0]=0; for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&val[i]),pre[i]=pre[i-1]+a[i]; dp[0]=0; for(int i=1;i<=n;i++){ for(int j=0;j<i;j++){ dp[i]=min(dp[i],dp[j]+(pre[i]-pre[j]+10)*val[i]); } } printf("%d ",dp[n]); } return 0; }
斜率优化:有点问题,下面队列维护的为下凸壳,为什么需要l+1<R
代码:
-----------------二更----------------
模仿bzoj 1010 hzw的单调队列写法,(ps:hzw写法中l首先赋值为1,r为0,que[++r]=0,这里r先进行++,在进行赋值,这样在写单调队列的时候就直接用que[r]作为队列末尾就行了,方便易思考)
下面讨论为什么维护下凸壳的原因,等待三更
#include <bits/stdc++.h> using namespace std; const int maxn=105; int a[maxn],val[maxn],dp[maxn],pre[maxn]; int que[maxn],l,r; double slop(int j,int k) { return (dp[j]-dp[k])*1.0/(pre[j]-pre[k]); } int main() { int T; scanf("%d",&T); while(T--){ int n; memset(dp,0x3f,sizeof(dp)); l=1,r=0; scanf("%d",&n); pre[0]=0; for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&val[i]),pre[i]=pre[i-1]+a[i]; dp[0]=0; que[++r]=0; for(int i=1;i<=n;i++){ while(l<r&&slop(que[l],que[l+1])<=val[i])l++; int j=que[l]; dp[i]=dp[j]+(pre[i]-pre[j]+10)*val[i]; while(l<r&&slop(que[r],que[r-1])>slop(que[r],i)) r--; que[++r]=i; } printf("%d ",dp[n]); } return 0; }