【bzoj1010】 HNOI2008—玩具裝箱toy


http://www.lydsy.com/JudgeOnline/problem.php?id=1010 (題目鏈接)

題意

  給定N個物品,可以連續的划分為若干個組,每個組的代價是(物品數-1+每個物品單獨的代價-L)^2,求最小代價

Solution

  決策單調性證明+斜率優化,轉自:http://blog.csdn.net/slongle_amazing/article/details/50330481

  很明顯我們得到朴素的轉移方程:${dp[i]=min(dp[j]+(i-j-1+sum[i]-sum[j]-L)^2),(0<=j<i)}$,時間復雜度為${O(n^2)}$

  我們定義:${f[i]=sum[i]+i,C=L+1}$,那么上式變成:${dp[i]=min(dp[j]+(f[i]-f[j]-C)^2),(0<=j<i)}$

  然后我們來證明決策的單調性

  假設在i處有兩個決策點${j,k(j<k)}$,且${k}$的決策比j好,

  即:${dp[j]+(f[i]-f[j]-C)^2>dp[k]+(f[i]-f[k]-C)^2——————[1]}$

  假設${i}$后面的某狀態${t}$有:${f[t]=f[i]+v (t>i)}$

  即證:$${dp[j]+(f[t]-f[j]-C)^2>dp[k]+(f[t]-f[k]-C)^2}$$

$${dp[j]+(f[i]+v-f[j]-C)^2>dp[k]+(f[i]+v-f[k]-C)^2}$$

$${dp[j]+(f[i]-f[j]-C)^2+2*v*(f[i]-f[j]-C)+v^2>dp[k]+(f[i]-f[k]-C)^2+2*v*(f[i]-f[k]-C)+v^2}$$

 

  由[1]我們得到:$${f[i]-f[j]-C>f[i]-f[k]-C}$$

$${f[k]>f[j]}$$

  顯然${f[i]}$單調遞增且${k>j}$,那么假設${[1]}$成立。

  展開${[1]}$:$${dp[j]+f[i]^2+(f[j]+c)^2-2*f[j]*(f[j]+C)>dp[k]+f[i]^2+(f[k]+C)^2-2*f[i]*(f[k]+C)}$$

$${dp[j]+(f[j]+C)^2-dp[k]-(f[k]+C)^2>2*f[i]*(f[j]-f[k])}$$

$${\frac{dp[j]-dp[k]+(f[j]+C)^2-(f[k]+C)^2}{2*(f[j]-f[k])}<f[i]}$$

  於是我們得到斜率${slope(j,k)}$:

$${slope(j,k)=\frac{dp[j]-dp[k]+(f[j]+C)^2-(f[k]+C)^2}{2*(f[j]-f[k])}}$$

$${有slope(j,k)<f[i]}$$

  所以當${j<k}$且${slope(j,k)<f[i]}$時,我們可以${O(1)}$判斷${k}$比${j}$更優。

  於是我們用單調隊列維護這個操作即可。

  當${slope(q[l],q[l+1])<f[i]}$時,${q[l+1]}$比${q[l]}$更優,pop隊首。

  當不滿足上凸性質,即${slope(q[r-1],q[r])>slope(q[r],i)}$時,pop隊尾。

代碼

// bzoj1010
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf (1ll<<60)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
const int maxn=50010;
int n,L;
LL a[maxn],f[maxn],s[maxn],dp[maxn],q[maxn];
 
double slope(LL a,LL b) {
    return (dp[a]-dp[b]+(f[a]+L)*(f[a]+L)-(f[b]+L)*(f[b]+L))/(2.0*(f[a]-f[b]));
}
int main() {
	scanf("%d%d",&n,&L);L++;
	for (int i=1;i<=n;i++) scanf("%lld",&s[i]),s[i]+=s[i-1];
	for (int i=1;i<=n;i++) f[i]=s[i]+i;
	int l=1,r=1;dp[1]=0;
	for (int i=1;i<=n;i++) {
		while (l<r && slope(q[l],q[l+1])<=f[i]) l++;
        dp[i]=dp[q[l]]+(f[i]-f[q[l]]-L)*(f[i]-f[q[l]]-L);
        while (l<r && slope(q[r-1],q[r])>slope(q[r],i)) r--;
        q[++r]=i;
    }
    printf("%lld",dp[n]);
    return 0;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM