BZOJ1010 [HNOI2008]玩具装箱
Description
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压
缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过
压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容
器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一
个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,
如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容
器,甚至超过L。但他希望费用最小.
Input
第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7
Output
输出最小费用
Sample Input
5 4
3
4
2
1
4
3
4
2
1
4
Sample Output
1
正解:斜率优化dp
解题报告:我还是太弱了,斜率优化都快忘记了,还是赶紧来复习一下吧
#include <iostream> #include <iomanip> #include <cstdlib> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #define ll long long #define ld long double #define RG register const int N = 100000; using namespace std; int gi(){ char ch=getchar();int x=0; while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } int f[N],c,head,tail,stack[N]; ll s[N],dp[N]; ld cmp(int x,int y){ return (ld)(s[y]*s[y]+2*s[y]*c+dp[y]-s[x]*s[x]-2*s[x]*c-dp[x])*1.0/(2.0*(ld)(s[y]-s[x])); } int main(){ freopen("toy.in","r",stdin); freopen("toy.out","w",stdout); int n=gi(),l=gi(); c=l+1; for (RG int i=1; i<=n; ++i) f[i]=gi(),s[i]=s[i-1]+f[i]; for (RG int i=1; i<=n; ++i) s[i]+=i; for (RG int i=1; i<=n; ++i){ while(head<tail && cmp(stack[head],stack[head+1])<=s[i]) ++head; dp[i]=dp[stack[head]]+(s[i]-s[stack[head]]-c)*(s[i]-s[stack[head]]-c); while(head<tail && cmp(stack[tail],i)<cmp(stack[tail-1],stack[tail])) --tail; stack[++tail]=i; } printf("%lld\n",dp[n]); return 0; }
--------------------------------------------------
1d1d好像也可以过
#include <iostream> #include <iomanip> #include <cstdlib> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #define RG register #define ll long long #define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout) const int N = 100000; using namespace std; int gi(){ char ch=getchar();int x=0; while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } ll f[N],dp[N]; int n,s,head,tail; struct date{ int l,r,p; }stack[N]; ll cal(int i,int v){ return dp[v]+(f[i]-f[v]+i-v-s)*(f[i]-f[v]+i-v-s); } int find(int l,int r,int i,int p){ int z=1,y=r,ans=r+1,mid; while(z<=y){ mid=(z+y)>>1; if (cal(mid,i)<cal(mid,p)) ans=mid,y=mid-1; else z=mid+1; } return ans; } int main(){ n=gi(),s=gi()+1,head=1,tail=1; for (RG int i=1; i<=n; ++i) f[i]=f[i-1]+gi(); stack[1]=(date){1,n,0}; for (RG int i=1; i<=n; ++i){ while(stack[head].r<i) ++head; dp[i]=cal(i,stack[head].p); int y=stack[tail].r; while(tail>head && stack[tail].l>i && cal(stack[tail].l,i)<cal(stack[tail].l,stack[tail].p)) --tail; if (head<=tail){ int t=find(stack[tail].l,stack[tail].r,i,stack[tail].p); if (t<=y){ stack[tail].r=t-1; stack[++tail]=(date){t,y,i}; } } } printf("%lld\n",dp[n]); }