zoukankan      html  css  js  c++  java
  • 题解 P3195 【[HNOI2008]玩具装箱TOY】

    题目链接

    刚学斜率优化,写个总结qaq

    Solution [HNOI2008]玩具装箱TOY

    题目大意:转移方程(f[i] = min{f[j]+(sum[i]-sum[j]+i-j-1-L)^2}),求(f[n])

    斜率优化


    分析:首先我们肯定不能(O(n^2))(dp),我们来拆一波式子,先把(min)符号去掉,然后令(L=L+1)

    (f[i] = f[j]+(sum[i]-sum[j]+i-j-1-L)^2)

    (f[i] = f[j]+(sum[i]-sum[j]+i-j-L)^2)

    考虑换元,用(s[i])代表(sum[i]+i)

    (f[i]=f[j]+(s[i]-s[j]-L)^2)

    完全平方公式

    (f[i]=f[j]+s[i]^2-2 imes s[i] imes (s[j]+L)+(s[j]+L)^2)

    然后我们发现有的和(i)有关,有的和(j)有关,有的和两个都有关,我们考虑将其分类:

    (i)有关的(f[i],s[i]^2)

    (j)有关的(f[j],(s[j]+L)^2)

    都有关的:(-2 imes s[i] imes (s[j]+L))

    我们考虑将其改写为(y=kx+b)的形式,将和(i)有关的作为(b),将和(i,j)都有关的作为(k,x),由于是乘积,我们将其中有(i)的项作为(k),和(j)有关的作为(x),然后将只和(j)有关的作为(y)

    所以

    (y=f[j]+(s[j]+L)^2)

    (k=2 imes s[i])

    (x=s[j]+L)

    (b=f[i]-s[i]^2)

    建立平面直角坐标系,以上文的(x,y)把决策点放进坐标系。然后我们发现问题变成了,一个坐标系内有若干个点,一个斜率不变的直线经过任意一个点,使得截距最小化

    我们往坐标系内加入决策点时,(x)坐标是递增的,一个显而易见的结论:有用的决策点的集合,过相邻点直线的斜率一定单调递增

    于是我们可以用单调队列来维护这个下凸壳使得斜率单调递增。

    那么我们如何这些决策点集合里面取最优呢,因为(k)是单调递增的,所以每次做决策时的直线斜率单调递增,一个点能成为决策点当且仅当左边直线的斜率比(k)小,右边直线的斜率比(k)大,又因为斜率单调递增,我们也可以用单调队列来维护,不断弹队头即可

    因为每个点只会进队/出队一次,所以时间复杂度是(O(n))

    #include <iostream>
    using namespace std;
    const int maxn = 5e4 + 100;
    typedef long long ll;
    int n,L,head,tail,q[maxn];
    ll sum[maxn],f[maxn];
    template <typename T>
    inline T square(const T &x){return x * x;}
    inline double s(int i){return sum[i] + i;}
    inline double k(int i){return 2 * s(i);}
    inline double y(int i){return f[i] + square(s(i) + L);}
    inline double x(int i){return s(i) + L;}
    inline double b(int i){return f[i] - square(s(i));}
    inline double slope(int i,int j){return (y(j) - y(i)) / (x(j) - x(i));}
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> L;L++;
    	for(int i = 1;i <= n;i++)
    		cin >> sum[i],sum[i] += sum[i - 1];
    	head = tail = 1;
    	for(int i = 1;i <= n;i++){
    		while(head < tail && slope(q[head],q[head + 1]) < k(i))head++;
    		f[i] = f[q[head]] + square(s(i) - s(q[head]) - L);
    		while(head < tail && slope(i,q[tail - 1]) < slope(q[tail - 1],q[tail]))tail--;
    		q[++tail] = i; 
    	}	
    	cout << f[n] << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    吴裕雄--天生自然 诗经:离思五首·其四
    吴裕雄--天生自然 诗经:江城子·乙卯正月二十日夜记梦
    CentOS6—启动httpd失败—Certificate has expired
    paper—SCI—Examples of author responses to reviewer comments
    paper—SCI答复审稿人的回信技巧
    mysql android—Installation using AndroPHP
    linux socket c : send data when socket close—SIGPIPE, Broken pipe
    Firefox:曾经打破黑暗的产品
    mysql中datetime到time_t转换
    mysql datetime 时间比较
  • 原文地址:https://www.cnblogs.com/colazcy/p/11738846.html
Copyright © 2011-2022 走看看