【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 */
以上为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 */
G102的孤儿们都要好好的啊。