这是一道斜率优化的题目
O(n2)
的算法很容易,
dp[i]=min(dp[j]+B[i].y∗A[i].x)
当然,先按X排个序,扫一遍,除掉不需要的,使得B中X递减,Y递增。
接下来考虑dp[i]究竟从哪里转移而来。
不妨设
j<k<i
如果
dp[j]+B[i].y∗B[j].x>dp[k]+B[i].y∗B[k].x
则我们会选k而非j,且以后也会选择k,因为以后的B[i].y逐渐增大,而B[j].x大于B[k].x 故前者的增长速度大于后者,后面的状态就用不到j,因此满足单调性。
我们可以将上面的式子移项成
(dp[k]−dp[j])/(B[j].x−B[k].x)<B[i].y
可以弄个函数去表示上诉式子的左边的值。(我用的是g(j,k))
当g(j,k)>sum[i]时j就无用了。
因为队列里还有一个插入。情况无非是
while(L<R&&g(stk[R-1],stk[R])>=g(stk[R],s))--R;
或while(L<R&&g(stk[R-1],stk[R])<=g(stk[R],s))--R;
若上面的情况成立:
1:
g(stk[R−1],stk[R])>=B[i].y
则stk[R-1]优,后者可舍去。
2:
g(stk[R−1],stk[R])<=B[i].y
则表示g(stk[R],i])<=B[i].y,stk[R]亦可舍去
代码片:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define M 50005
int n,m,tot;
struct node{
int x,y;
bool operator<(const node &A)const{
if(x!=A.x)return x>A.x;
return y>A.y;
}
}A[M],B[M];
long long dp[M];
//int stk[M];
int L,R=-1;
pair<int ,int> stk[M];
double g(pair<int ,int > a,pair<int ,int > b){
return 1.0*(dp[a.first]-dp[b.first])/(b.second-a.second);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d %d",&A[i].x,&A[i].y);
sort(A+1,A+1+n);
/*O(n*n)
for(int i=1;i<=n;i++){
if(m>=A[i].y)continue;
m=A[i].y;
B[++tot]=A[i];
}
for(int i=1;i<=tot;i++){
int y=B[i].y;
dp[i]=dp[i-1]+y*B[i].x+1;
for(int j=i;j;j--)
if(dp[i]>dp[j-1]+1ll*y*B[j].x)dp[i]=dp[j-1]+1ll*y*B[j].x;
}
cout<<dp[tot]<<endl;
*/
/*
for(int i=1;i<=n;i++){
if(B[tot].y>=A[i].y)continue;
B[++tot]=A[i];
B[tot-1].x=B[tot].x;
}
stk[++R]=0;
for(int i=1;i<=tot;i++){
int y=B[i].y;
while(L<R&&g(stk[L],stk[L+1])<=y)++L;//右比左优且以后也比左优
dp[i]=1ll*dp[stk[L]]+1ll*B[stk[L]].x*y;
while(L<R&&g(stk[R-1],stk[R])>=g(stk[R],i))--R;//R-1的比R优,now比R优,R就没必要
stk[++R]=i;
}
cout<<dp[tot]<<endl;
*/
//下面只为锻炼如何使用pair
for(int i=1;i<=n;i++){
if(B[tot].y>=A[i].y)continue;
B[++tot]=A[i];
B[tot-1].x=B[tot].x;
}
stk[++R]=make_pair(0,B[0].x);
for(int i=1;i<=tot;i++){
int y=B[i].y;
while(L<R&&g(stk[L],stk[L+1])<=y)++L;//右比左优且以后也比左优
dp[i]=1ll*dp[stk[L].first]+1ll*stk[L].second*y;
pair<int ,int > s=make_pair(i,B[i].x);
while(L<R&&g(stk[R-1],stk[R])>=g(stk[R],s))--R;//R-1的比R优,now比R优,R就没必要
stk[++R]=s;
}
cout<<dp[tot]<<endl;
return 0;
}
本人还写了一些题:
仓库建设,特别行动队,玩具装箱,小P的牧场。
有些应该是USACO的dp题。
如果需要题解,请留言联系。