zoukankan      html  css  js  c++  java
  • bzoj3437 小P的牧场

    Description


     背景

        小P是个特么喜欢玩MC的孩纸。。。

     描述

        小P在MC里有n个牧场,自西向东呈一字形排列(自西向东用1…n编号),于是他就烦恼了:为了控制这n个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量,在第i个牧场建立控制站的花费是ai,每个牧场i的放养量是bi,理所当然,小P需要总花费最小,但是小P的智商有点不够用了,所以这个最小总花费就由你来算出啦。

    Input

        第一行一个整数 n 表示牧场数目

        第二行包括n个整数,第i个整数表示ai

        第三行包括n个整数,第i个整数表示bi

    Output

       只有一行,包括一个整数,表示最小花费

    Sample Input

    4
    2424
    3142

    Sample Output


    9

    样例解释

    选取牧场1,3,4建立控制站,最小费用为2+(2+1*1)+4=9。

    数据范围与约定


    对于100%的数据,1<=n<=1000000,0<ai,bi<=10000

    斜率优化的dp

    有点麻烦

    f[i]表示1~i中在i放控制站的最小代价

    那么f[i]=min(f[j]+a[i]+Σb[k]*(i-k)|j<k<=i)

    然后算Σ的式子的时候首先b[i]可以用前缀和优化一下

    首先原式

    =s[i-1]-s[j]

    +s[i-2]-s[j]

    +s[i-3]-s[j]

    ……

    +s[j+1]-s[j]

    所以再搞出s[]的前缀和t[]

    那么最后化简完f[i]=min(f[j]+a[i]+t[i-1]-t[j]-s[j]*(i-j-1));

    然后考虑转移i的状态的时候,有j,k两个决策

    当f[j]+a[i]+t[i-1]-t[j]-s[j]*(i-j-1)<f[k]+a[i]+t[i-1]-t[k]-s[k]*(i-k-1)时j比k优

    即f[j]-s[j]-(f[k]-s[k])+s[j]*(j+1)-s[k]*(k+1)<i*(s[j]-s[k])

    于是可以用斜率优化了

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<deque>
    #include<set>
    #include<map>
    #include<ctime>
    #define LL long long
    #define inf 10000000000000000ll
    #define pa pair<int,int>
    #define pi 3.1415926535897932384626433832795028841971
    #define N 1000010
    using namespace std;
    inline LL read()
    {
        LL x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    LL s[N],t[N],f[N];
    int a[N],b[N];
    int q[N],head,tail=1;
    LL cala(int x,int y)
    {
    	return f[x]-f[y]-(t[x]-t[y])+(s[x]*(x+1)-s[y]*(y+1));
    }
    LL calb(int x,int y)
    {
    	return s[x]-s[y];
    }
    int n;
    int main()          //f[i]=min(f[j]+a[i]+t[i-1]-t[j]-s[j]*(i-j-1));
    {
    	freopen("pasture.in","r",stdin);
    	freopen("pasture.out","w",stdout);
    	n=read();
    	for (int i=1;i<=n;i++)f[i]=inf;
    	for (int i=1;i<=n;i++)a[i]=read();
    	for (int i=1;i<=n;i++)b[i]=read();
    	for (int i=1;i<=n;i++)
    	{
    		s[i]=s[i-1]+b[i];
    		t[i]=t[i-1]+s[i];
    	}
    	for (int i=1;i<=n;i++)
    	{
    		while (tail-head>1 && cala(q[head+1],q[head])<=i*calb(q[head+1],q[head]))head++;
    		int from=q[head];
    		f[i]=f[from]+a[i]+t[i-1]-t[from]-s[from]*(i-from-1);
    		q[tail++]=i;
    		for (int k=tail-2;k>head;k--)
    		{
    			int x=q[k+1],y=q[k],z=q[k-1];
    			if (cala(y,z)*calb(x,y)>=cala(x,y)*calb(y,z))q[k]=q[--tail];
    			else break;
    		}
    	}
    	printf("%lld
    ",f[n]);
    }
    

      

    ——by zhber,转载请注明来源
  • 相关阅读:
    最近ACM刷题见到的没见过的名词
    最近刷题常常遇见的需要百度的知识点
    简单RPG场景实现(改
    简单RPG场景实现
    位图载入与位图移动
    动态菜单
    静态菜单
    双人五子棋
    HDU 2112 HDU Today
    音痴又音痴的LT
  • 原文地址:https://www.cnblogs.com/zhber/p/4130567.html
Copyright © 2011-2022 走看看