zoukankan      html  css  js  c++  java
  • 【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;
    }
    

      

  • 相关阅读:
    hdu1242 Rescue BFS广搜 + 优先队列
    hdu 1430 魔板
    康托展开
    hdu 4394 Digital Square(bfs)
    hdu 1969 Pie
    KMP模板
    hdu 1846 Brave Game
    循环赛日程表
    hdu 1022 Train Problem I
    整数划分问题
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5968118.html
Copyright © 2011-2022 走看看