zoukankan      html  css  js  c++  java
  • Luogu P2900 [USACO08MAR]土地征用Land Acquisition

    这是一道有技巧的斜率优化题。(不会斜率优化,请戳这里)

    ai,biia_i,b_i分别为第i块土地的长、宽

    首先,我们按长为第一关键字,宽为第二关键字排序,使得长为非下降序列,当长相等时,宽为非下降序列。因为如果一块土地长,宽都大,就可以把比它长宽都小的土地吃掉,所以我们排序后,再删去一些不需要保留的土地,使得所有土地的宽单调递减。

    #define a(i) a[i].a
    #define b(i) a[i].b
    struct node
    {
    	ll a,b;
    	bool operator <(node c)const{return a==c.a?b<c.b:a<c.a;}//这是重载运算符
    }a[N];
    //bool cmp(node x,node y){return x.a==y.a?x.b<y.b:x.a<y.a;}
    //重载运算符不会打,那就只打上面的一行。
    
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++)
    			scanf("%lld%lld",&a(i),&b(i));
    		sort(a+1,a+n+1);
    		int t=1;
    		for(int i=2;i<=n;i++)
    		{
    			while(t&&b(i)>=b(t))t--;
    			a[++t]=a[i];
    		}
    		n=t;
    

    为什么要这样处理呢? 证明:
    i&lt;j&lt;kai&lt;aj&lt;akbi&gt;bj&gt;bki&lt;j&lt;k且a_i&lt;a_j&lt;a_k且b_i&gt;b_j&gt;b_k,我们选择i,kji,k为一块,j为一块的话,费用为akbi+ajbja_k*b_i+a_j*b_j。但是,i,j,kakbi把i,j,k分成一块的费用只需a_k*b_i。
    所以,我们排序、删土地后,要取连续的一段。

    接着,我们设f[i]f[i]表示对前ii块土地分成若干个连续块的最小费用。
    则有:f[i]=min  f[j1]+aibj   (0&lt;j&lt;i)f[i]=min~~{f[j-1]+a_i*b_j}~~~(0&lt;j&lt;i)
    把它转化为y=kx+by=kx+b的形式:
    f[j1]=(ai)bj+f[i]f[j-1]=(-a_i)*b_j+f[i]
           y     =     k      x  +  b~~~~~~~y~~~~~=~~~~~k~~~~~~x~~+~~b
    认真看链接的同学知道用斜率优化的题有以下性质:

    1.

    斜率(kai)(k,即本题中的-a_i)具有单调性.

    2.

    横坐标x(x)单调递增

    3.

    决策点(继承点)有序。
    一般来说,当前处理的状态(如此题中的f[i]f[i])前面符号正负最好与取最大值还是最小值有关。
    对笔者而言,取最小值时前面符号最好为正,反之最好为负。

    但是,上面的bjb_j并不单调递增啊。
    没事,我们可把上式变为:f[j1]=ai(bj)+f[i]f[j-1]=a_i*(-b_j)+f[i]
    这样,k,xf[i],k,x都单调递增,且满足f[i]前面是正号,就可以用斜率优化了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define a(i) a[i].a
    #define b(i) a[i].b
    using namespace std;
    typedef long long ll;
    const int N=5e4+10;
    int n,q[N],l,r;
    ll f[N];
    struct node
    {
    	ll a,b;
    	bool operator <(node c)const{return a==c.a?b<c.b:a<c.a;}
    }a[N];
    inline ll x(int i){return -b(i+1);}
    inline ll y(int i){return f[i];}
    inline bool pd(int i,int j,int k)
    {
    	return (y(j)-y(i))*(x(k)-x(j))<(y(k)-y(j))*(x(j)-x(i));
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%lld%lld",&a(i),&b(i));
    	sort(a+1,a+n+1);
    	int t=1;
    	for(int i=2;i<=n;i++)
    	{
    		while(t&&b(i)>=b(t))t--;
    		a[++t]=a[i];
    	}
    	n=t;
    	l=r=1;q[1]=0;
    	for(int i=1;i<=n;i++)
    	{
    		while(l<r&&y(q[l+1])-y(q[l])<=a(i)*(x(q[l+1])-x(q[l])))l++;
    		int j=q[l];
    		f[i]=f[j]+b(j+1)*a(i);
    		while(l<r&&!pd(q[r-1],q[r],i))r--;
    		q[++r]=i;
    	}
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    工作的本质是思考
    V8、JSCore、Hermes、QuickJS,hybrid开发JS引擎怎么选
    Aspects框架的源码解读及问题解析
    饿了么移动APP的架构演进
    关键字:客户端架构演进
    以小见大,见微知著——亿万级APP架构演进之路
    理解 Swift:ObjectiveC 的构建管道
    MMKV 组件现在开源了
    进阶:iOS 性能优化系列
    你如果无法度量它,就无法管理它
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373914.html
Copyright © 2011-2022 走看看