zoukankan      html  css  js  c++  java
  • bzoj1010[HNOI2008] 玩具装箱toy(带斜率优化学习笔记)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1010

    题目大意:

    有n个数,分成连续的若干段,每段(假设从第j个到第i个组成一段)的分数为 (X-L)^2,X为j-i+Sigma(Ck) i<=k<=j,其中L是一个常量。目标:各段分数的总和最小。

    题解:

    斜率优化 

    ===============带个笔记(总结)~================

    斜率优化学了两种方法之后觉得截距式很好用啊

    写出dp方程之后就有目的的去化式子了

    于是所以我们的目标是要化成f[i]=a[i]*b[j]+c[j]+(一个只与i有关的常数)这个形式!

    [a[i]表示一个与i有关的数,b[j]、c[j]亦如此]

    移项:-a[i]*b[j]+f[i]=c[j] 有没有很像y=kx+b

    把-a[i]看为斜率,b[j]为x,c[j]为y,画一条直线 

    那么答案f[i]就是直线与y轴的交点,即截距

    而为什么去维护上/下凸包可以理解成线性规划~

    这两篇都是讲斜率优化的

    截距式的,看这个看懂了~http://blog.csdn.net/balloons2012/article/details/7912296

    ↓这个就是各种化?单调队列写得挺好的,然而斜率优化其实并不怎么看懂ORZORZ

    http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html

    ==================真の题解====================


    至少先把dp方程写出来吧:f[i]=min( f[j] +[sum[i]-sum[j]+i-(j+1)-L]^2 ),j<=i (sum[i]为前缀和 

    f[i]表示i为其中一个断点,搞完前i个数的最小总和

    为了简化方程,我们设s[i]=sum[i]+i;L=L+1;

    那么原方程则为 f[i]=min(f[j]+(s[i]-s[j]-L)^2),j<=i

    平方拆开、移项能得到:2*(s[i]-L)*s[j]+f[i]=f[j]+s[j]^2

    k=2*(s[i]-L);x=s[j];y=f[j]+s[j]*2;

    因为求最小值 故维护一个下凸包

    p.s.可能我的式子把常数那个部分给吃了orz草稿太乱看不清之前推的式子了大概就这样吧~

    代码代码:

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define maxn 50100
    
    LL s[maxn],list[maxn];LL f[maxn];
    double Y(LL j) {return f[j]+s[j]*s[j];}
    double X(LL j) {return s[j];}
    double slop(LL j,LL k)
    {
    	return (Y(k)-Y(j))/(X(k)-X(j));
    }
    int main()
    {
    	//freopen("a.in","r",stdin);
    	//freopen("a.out","w",stdout);
    	LL n,L,i,x,head,tail;
    	scanf("%lld%lld",&n,&L);L++;s[0]=0;
    	for (i=1;i<=n;i++) {scanf("%lld",&s[i]);s[i]+=s[i-1];}
    	for (i=1;i<=n;i++) s[i]+=i;
    	head=1;tail=1;list[1]=0;
    	for (i=1;i<=n;i++)
    	{
    		while (head<tail && slop(list[head],list[head+1])<=2*(s[i]-L)) head++;
    		int j=list[head];
    		f[i]=f[j]+(s[i]-s[j]-L)*(s[i]-s[j]-L);
    		while (head<tail && slop(list[tail-1],list[tail])>slop(list[tail],i)) tail--;
    		list[++tail]=i;
    	}
    	printf("%lld
    ",f[n]); 
    	return 0;
    }


  • 相关阅读:
    扩展中国剩余定理
    bzoj 3816&&uoj #41. [清华集训2014]矩阵变换
    THUSC2017
    bzoj 4521: [Cqoi2016]手机号码
    bzoj 4871: [Shoi2017]摧毁“树状图”
    bzoj 2300 : [HAOI2011]防线修建
    bzoj 3853 : GCD Array
    HEOI 2017 游记
    bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机模板
    bzoj 4310 跳蚤
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527867.html
Copyright © 2011-2022 走看看