斜率优化问题一般都是决策单调问题。对于这题可以证明单调决策。
令sum[i]=sigma(c [k] ) 1<=k<=i , f[i]=sum[i]+i , c=L+1;
首先我们可以写出转移方程 dp[i] = min( dp[j] + (f[i]-f[j]-c)^2 ) 。令决策j1<j2,若决策j2更优有
dp[j2]+(f[i]-f[j2]-c)^2<=dp[j1]+(f[i]-f[j1]-c)^2
可以得带 ((dp[j2]+f[j2]^2)-(dp[j1]+f[j1]^2) )/(f[j2]-f[j1])<2*(f[i]-c)。
优于f[i]是递增的,所以对于t>i的点,决策j2总是比j1更优,那么j1实际上可以从决策集合中删除。后面的就可以用一个队列维护了。
<span style="font-size:14px;">#include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <string> #include <cctype> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int inf = 0x3fffffff; const int mmax =50010; LL C[mmax]; LL L,c; LL sum[mmax],f[mmax],dp[mmax]; LL sqr(LL x) { return x*x; } double G(int x) { return 1.0*f[x]*f[x]+dp[x]; } double S(int x) { return 2.0*f[x]; } void calc(int i,int j) { dp[i]=dp[j]+sqr(f[i]-f[j]-c); } int Q[mmax]; int main() { int n; while(cin>>n>>L) { c=L+1; sum[0]=0; f[0]=0; for(int i=1;i<=n;i++) { scanf("%lld",&C[i]); sum[i]=sum[i-1]+C[i]; f[i]=sum[i]+i; } int head=0,tail=-1; dp[0]=0; Q[++tail]=0; for(int i=1;i<=n;i++) { while(head<tail) { double tmp=1.0*(G(Q[head+1])-G(Q[head]))/(S(Q[head+1])-S(Q[head])); if(tmp<=f[i]-c) head++; else break; } calc(i,Q[head]); while(head<tail) { double tmp1=1.0*(G(Q[tail])-G(Q[tail-1]))/(S(Q[tail])-S(Q[tail-1])); double tmp2=1.0*(G(i)-G(Q[tail]))/(S(i)-S(Q[tail])); if(tmp1>=tmp2) tail--; else break; } Q[++tail]=i; } printf("%lld\n",dp[n]); } return 0; } </span>
原文地址:http://blog.csdn.net/u012127882/article/details/46681651