BZOJ斜率优化水题集

[BZOJ 1010]

显然,用dp[i]表示前i个玩具所需最小费用,则有

dp[i]=min{dp[j]+cost(i,j+1)}

cost(i,j)表示i~j的玩具塞入一个容器的代价

即设有j>k且dp[j]+cost(i,j+1)<dp[k]+cost(i,k+1)

解得当(dp[j]-dp[k]+(j+c[j])^2-(k+c[k])^2)/((j+c[j]-k-c[k])*2)<i-1+c[i]-L时j比k优

即代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 50000 +100
#define pf(x) ((x)*(x))
using namespace std;
typedef long long ll;
ll dp[maxn],L,que[maxn],c[maxn];
int n,l,r;
double calc(int j,int k){
    return (double)(dp[j]-dp[k]+pf(j+c[j])-pf(k+c[k]))/
                    2/(double)(j+c[j]-k-c[k]);
}
int main(){
    scanf("%d%d",&n,&L);
    for(int i=1;i<=n;++i)
        scanf("%lld",&c[i]),c[i]+=c[i-1];
    for(int i=1;i<=n;++i){
        while(l<r&&calc(que[l+1],que[l])<i-1+c[i]-L)l++;
        int t=que[l];
        dp[i]=dp[t]+pf(i-t-1+c[i]-c[t]-L);
        while(l<r&&calc(i,que[r])<calc(que[r],que[r-1]))r--;
        que[++r]=i;
    }
    printf("%lld",dp[n]);
}


[BZOJ 2351]

用dp[i]表示1~i的村庄到B地花费的最小代价

则有dp[i]=min{dp[j]+A(在j+1修站时j+1~i的村民到B地的最小代价)}

A即是这些村民原本到b的代价-村民个数*站到B地距离.

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 40100
typedef long long ll;
struct data{
    ll t,r;
    data(){}
    data(int t):r(0),t(t){}
    bool operator<(const data& d)const{
        return t<d.t;
    }
    bool operator==(const data& d)const{
        return t==d.t;
    }
    void scan(){
        scanf("%lld%lld",&t,&r);
    }
};
ll dp[maxn];
int n,m,q[maxn],l,r;
data d[maxn],s[maxn];
double calc(int j,int k){
    return (double)(dp[j]-dp[k]+s[k].t-s[j].t+1.0*d[j+1].t*d[j].r-1.0*d[k].r*d[k+1].t)/(double)(d[j+1].t-d[k+1].t);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)d[i].scan();
    sort(d+1,d+n+1);
    for(int i=1;i<=n;++i)s[i].t=d[i].t*d[i].r;
    for(int i=1;i<=n;++i)s[i].t+=s[i-1].t;
    for(int i=1;i<=n;++i)d[i].r+=d[i-1].r;
    q[l=r=1]=0;
    for(int i=1;i<=n;++i){
        dp[i]=s[i].t-s[0].t;
        while(l<r&&calc(q[l+1],q[l])<d[i].r)l++;
        int x=q[l];
        dp[i]=min(dp[i],dp[x]+s[i].t-s[x].t-d[x+1].t*(d[i].r-d[x].r)+m);
        while(l<r&&calc(i,q[r])<calc(q[r],q[r-1]))r--;
        q[++r]=i;
    }
    printf("%lld\n",dp[n]);
         
}
注意:不要恶(ao)意(miao)去(chong)重,数据是 精心设计


[BZOJ 3675]

懒得解释了,解一下不等式即可

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll dp[101000][2],s[101000];
int que[101000],n,k,l,r,f=0;
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
        scanf("%lld",&s[i]),s[i]+=s[i-1];
    for(int i=1;i<=k;++i,f=!f){
        que[l=r=0]=i-1;
        for(int j=i;j<=n;++j){
             
            while(l<r&&dp[que[l]][!f]-dp[que[l+1]][!f]<=(s[n]-s[j])*(s[que[l]]-s[que[l+1]]))l++;
        //  printf("[%I64d]",s[n]-s[j]);
            dp[j][f]=max(dp[j][f],dp[que[l]][!f]+(s[n]-s[j])*(s[j]-s[que[l]]));
        //  printf("dp[%d][%d] cho=%d +%I64d*%I64d =>%I64d\n",j,f,que[l],(s[n]-s[j]),(s[j]-s[que[l]]),dp[j][f]);
            while(l<r&&(dp[j][!f]-dp[que[r]][!f])*(s[que[r]]-s[que[r-1]])>=
                    (dp[que[r]][!f]-dp[que[r-1]][!f])*(s[j]-s[que[r]]))r--;
            que[++r]=j;
        }
    }
    ll ans=0;
    for(int i=k;i<=n;++i)ans=max(ans,dp[i][!f]);
    printf("%lld",ans);
         
     
}


[BZOJ 1911]

懒得解释了 Water~~~

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cctype>
#define maxn 1000000 + 100
using namespace std;
typedef long long ll;
ll dp[maxn],s[maxn];
int n,a,b,c,sol[maxn],que[maxn],l=1,r=1;
void readint(int &x){
    char act=0;
    while(!isdigit(act=getchar()));
    x=act-'0';
    while(isdigit(act=getchar()))x=(x<<3)+(x<<1)+act-'0';
}
double inline calc(int j,int k){
    return (double)(a*(s[j]*s[j]-s[k]*s[k])+dp[j]-dp[k]+b*(s[k]-s[j]))/(double)(2*a*(s[j]-s[k]));
}
ll inline gdp(int i,int j){
    ll x=s[i]-s[j];
    return a*x*x+b*x+c;
}
int main(){
    scanf("%d%d%d%d",&n,&a,&b,&c);
    for(int i=1;i<=n;++i)readint(sol[i]);
    for(int i=1;i<=n;++i)s[i]=s[i-1]+sol[i];
    for(int i=1;i<=n;++i){
        while(l<r&&calc(que[l+1],que[l])<s[i])l++;
        dp[i]=gdp(i,que[l])+dp[que[l]];
        while(l<r&&calc(que[r],i)<calc(que[r],que[r-1]))r--;
        que[++r]=i;
    }
    printf("%lld",dp[n]);
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值