【Luogu 3195】玩具装箱

【题目链接】传送门

【写在前面】

先写了个n^2的简单dp,这永远都是写题的第一步。

状态开始会想到要设置成到第i个玩具分成了j批,但是并不知道分成多少批。

直接将状态设置为分到第i个玩具的最小花费,这个类似任务安排里将三维的n^3变成一维的n^2。

【code】

#include<bits/stdc++.h>
using namespace std;
#define File "toy"
#define ll long long
#define ull unsigned long long
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
inline ll read(){
    ll x=0,f=1;   char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
const int mxn = 5e4+5;
ll n,l;
ll sc[mxn],f[mxn];
int main(){
    file();
    n = read(),l = read();
    for(int i = 1;i <= n; ++i) sc[i] = sc[i-1]+read();
    memset(f,0x3f,sizeof f);
    f[0] = 0;
    for(int i = 1;i <= n; ++i)
        for(int j = 0;j < i; ++j)
            f[i] = min(f[i],f[j]+(i-j-1+sc[i]-sc[j]-l)*(i-j-1+sc[i]-sc[j]-l));
    printf("%lld\n",f[n]);
    return 0;
}
/*
5 4
3
4
2
1
4
*/
View Code

 以上为n^2的暴力,在luogu上20在校oj60。

【题解大意】

好的开始推斜率优化的式子。

给我的启示就是,

除了移项大法求斜率优化的式子,

还可以有,

假设两个决策是将当前 i 转移的决策点x,y的状态,

不妨假设x,y大小值关系和dp值的大小关系,

然后再大力移项,这样思路就会清晰很多。

所谓的斜率优化其实就是找到单调性,

只不过是两个值对应着坐标轴中相应的斜率。 

【code】

#include<bits/stdc++.h>
using namespace std;
#define File ""
#define ll long long
#define ull unsigned long long
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
inline ll read(){
    ll x=0,f=1;   char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
const int mxn = 5e4+5;
ll n,L,s;
int l,r;
int q[mxn];
ll f[mxn],dp[mxn],g[mxn];
inline double slope(int y,int x) {
    return (double)(dp[x]+g[x]-(dp[y]+g[y]))/(f[x]-f[y]);
}
int main(){
//    file();
    n = read(),L = read();
    for(int i = 1; i <= n; ++i) s+=read(),f[i]=s+i,g[i] = (f[i]+L+1)*(f[i]+L+1);
    g[0] = (L+1)*(L+1);
    for(int i = 1; i <= n; ++i){
        while(l<r && 2*f[i] >= slope(q[l],q[l+1])) l++;
        dp[i] = dp[q[l]] + (f[i]-f[q[l]]-1-L)*(f[i]-f[q[l]]-1-L);
        while(l<r && slope(q[r],i) < slope(q[r-1],q[r])) r--;
        q[++r] = i;
    }
//    for(int i = 1;i <= n; ++i) printf("%d ",f[i]);
//    puts("");
//    for(int i = 1;i <= n; ++i) printf("%d ",g[i]);
//    puts("");
    printf("%lld\n",dp[n]);
    return 0;
}
/*
5 4
3
4
2
1
4
*/
View Code

 

posted @ 2019-05-08 16:41  ve-2021  阅读(159)  评论(0编辑  收藏  举报