斜率优化dp
算法理解
建议食用题解再结合一本通题解,一下就明白了
讲的非常清楚
本质上是我们发现现在已知 \(k\) 想要求 \(b\) 最小,其中有很多个 \((x,y)\) 可以进行计算答案,找到一个 \((x,y)\) 可以使 \(b\) 最小,博客的内容就是具体怎么做
T1,2
代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e4+5;
int n,S;
int sumc[N],sumt[N],c[N],t[N],f[N];
struct coo{
int x,y;
}que[N];
bool comk1(coo p1,coo p2,coo p3,coo p4){
if((p2.y-p1.y)*(p4.x-p3.x)<(p4.y-p3.y)*(p2.x-p1.x)) return 1;
else return 0;
}
bool comk2(coo p1,coo p2,int k){
if((p2.y-p1.y)<k*(p2.x-p1.x)) return 1;
else return 0;
}
struct monqueue{
int l,r;
int len(){
return r-l+1;
}
void init(){
que[1]={0,0};
l=1,r=1;
}
void add(int x,int y){
coo k={x,y};
if(len()<2){
que[++r]=k;
return;
}
while(len()>=2&&!comk1(que[r-1],que[r],que[r],k)){
r--;
}
que[++r]=k;
}
int query(int k,int i){
while(len()>=2&&comk2(que[l],que[l+1],k)){
l++;
}
coo top=que[l];
int b=top.y-top.x*k;
return b+S*sumc[n]+sumt[i]*sumc[i];
}
}q;
void solve(){
q.init();
for(int i=1;i<=n;i++){
sumt[i]=sumt[i-1]+t[i];
sumc[i]=sumc[i-1]+c[i];
}
for(int i=1;i<=n;i++){
f[i]=q.query(S+sumt[i],i);
q.add(sumc[i],f[i]);
}
}
signed main(){
scanf("%lld%lld",&n,&S);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&t[i],&c[i]);
}
solve();
printf("%lld\n",f[n]);
}
T3:
因为斜率不单调,多一个二分
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5;
int n,S;
int sumc[N],sumt[N],c[N],t[N],f[N];
struct coo{
int x,y;
}que[N];
bool comk1(coo p1,coo p2,coo p3,coo p4){
if((p2.y-p1.y)*(p4.x-p3.x)<(p4.y-p3.y)*(p2.x-p1.x)) return 1;
else return 0;
}
bool comk2(coo p1,coo p2,int k){
if((p2.y-p1.y)<k*(p2.x-p1.x)) return 1;
else return 0;
}
struct monqueue{
int l,r;
int len(){
return r-l+1;
}
void init(){
que[1]={0,0};
l=1,r=1;
}
void add(int x,int y){
coo k={x,y};
if(len()<2){
que[++r]=k;
return;
}
while(len()>=2&&!comk1(que[r-1],que[r],que[r],k)){
r--;
}
que[++r]=k;
}
int dic(int k){
if(len()==1) return l;
if(comk2(que[r-1],que[r],k)) return r;//特判所有斜率都小于k的情况
int ml=l,mr=r-1;//前一个点代表斜率
while(ml<mr){
int mid=(ml+mr)>>1;
if(comk2(que[mid],que[mid+1],k)) ml=mid+1;
else mr=mid;
}
return ml;
}
int query(int k,int i){
coo now=que[dic(k)];
int b=now.y-now.x*k;
return b+S*sumc[n]+sumt[i]*sumc[i];
}
}q;
void solve(){
q.init();
for(int i=1;i<=n;i++){
sumt[i]=sumt[i-1]+t[i];
sumc[i]=sumc[i-1]+c[i];
}
for(int i=1;i<=n;i++){
f[i]=q.query(S+sumt[i],i);
q.add(sumc[i],f[i]);
}
}
signed main(){
scanf("%lld%lld",&n,&S);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&t[i],&c[i]);
}
solve();
printf("%lld\n",f[n]);
}

浙公网安备 33010602011771号