zoukankan      html  css  js  c++  java
  • BZOJ1010玩具装箱[DP+单调性优化]

    题目意思我就不多说了。

    基本的DP很容易想到的。

    设f[i]为前i个玩具放到箱子里面的最小代价。

    int a = sum[i] - sum[j] + i - j - 1 - L;

    那么f[i] = min(f[j] + a * a);

    但是这样去转移的话需要n^2的复杂度。。这样的话就会TLE。

    这里的话我们就可以应用到单调性优化或者斜率优化。

    先了解一下单调性优化可以用在什么地方。

    我们可以证明出对于任意的一个i,他的决策点是j,为了保持最优解,那么在i从1到n的过程中,每一个状态的决策点j都是不下降的。

    怎么证明这里就不说了。

    然后说一下具体的单调优化的方法

    先讲一下几个数组的意思,sta[i]代表第i个状态(也就是f[i])转移的决策点的编号(编号就是第几大)

    l[sta[i]]代表这个决策点编号决策的状态的区间左边节点

    for(int i = 1 ; i <= n ; ++i)首先枚举i

    然后利用二分查找

    int find(int x)
    {
    int left = 1 , right = r , mid = (left + right) / 2;
    while(left <= right)
    {
    if(l[sta[mid]] == x) return mid;
    if(l[sta[mid]] < x) left = mid + 1;
    else right = mid - 1;
    mid = (left + right) / 2;
    }
    return right;
    }

    我也不知道怎么描述这个呀。。。大概就是查找i在哪个决策点的区间里。

    然后根据编号转移。

    接着需要动态的更新sta中其他点的决策点

    找到大概在哪个区间,然后对这个区间再二分找具体的某个点

    然后更新就ok了

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define mod 9999973
    #define N 50005
    #define ll long long
    using namespace std;
    int n , L , c[N] , l[N] , sta[N] , left , right , r;
    ll sum[N] , f[N];
    ll turn(int j , int i)
    {
    	ll x = i - j + sum[i] - sum[j] - 1;
    	return f[j] + (x - L) * (x - L);
    }
    int find(int x)
    {
    	int left = 1 , right = r , mid = (left + right) / 2;
    	while(left <= right)
    	{
    		if(l[sta[mid]] == x) return mid;
    		if(l[sta[mid]] < x) left = mid + 1;
    		else right = mid - 1;
    		mid = (left + right) / 2;
    	}
    	return right;
    }
    void work()
    { 
    	scanf("%d%d", &n, &L);
    	for(int i = 1 ; i <= n ; ++i) scanf("%d", &c[i]) , sum[i] = sum[i - 1] + c[i];
    	for(int i = 1 ; i <= n ; ++i) l[i] = n + 1;
    	memset(sta , 255 , sizeof(sta));
    	l[0] = 1 , sta[1] = 0 , r = 1;
    	for(int i = 1 ; i <= n ; ++i)
    	{
    		f[i] = turn(sta[find(i)] , i);
    		while(r && l[sta[r]] > i && turn(i , l[sta[r]]) < turn(sta[r] , l[sta[r]])) --r;
    		if(!r)
    		{
    			sta[++r] = i;
    			l[i] = i;
    			continue;
    		}
    		int left = l[sta[r]] , right = n , mid = (left + right) / 2;
    		while(left <= right)
    		{
    			if(turn(i , mid) > turn(sta[r] , mid)) left = mid + 1;
    			else right = mid - 1;
    			mid = (left + right) / 2;
    		}
    		if(turn(i , left) > turn(sta[r] , left)) continue;
    		sta[++r] = i , l[i] = left;
    	}
    	printf("%lld
    ", f[n]);
    }
    int main()
    {
    	work();
    	return 0;
    }
    

      

  • 相关阅读:
    爱情七十八课,闲了就“犯贱”
    阿里巴巴中文站的CSS设计规则(转)
    爱情八十一课,可预测的分手
    [性格][管理]《九型人格2》 唐·理查德·里索(美)、拉斯·赫德森(美)
    爱情八十二课,爱情三国杀
    爱情七十九课,不爱权力大
    [心理学]《爱情心灵安全岛》 四四
    一些你不知道的囧知识,保证让你崩溃
    爱情七十四课,我们的意义
    爱情七十六课,门当户对
  • 原文地址:https://www.cnblogs.com/lalawu/p/3561079.html
Copyright © 2011-2022 走看看