[USACO08MAR]土地征用Land Acquisition

谁说胖子不能爱 提交于 2019-12-27 03:27:22

题目链接

首先我们按照长度从大到小排序,这样我们考虑宽就可以了,我们发现这样一个事情:


其中我们发现红色的点可以直接被删去,以为它们一定会被两侧的点覆盖。

于是我们的所求就是:

f[i]=minj=0i1(f[j]+a[j+1]×b[i])f[i]=min_{j=0}^{i-1}(f[j]+a[j+1] \times b[i])

然后我们发现f[i]f[i]是凸的,于是我们单调栈++二分就可以了,具体做法详见:[HNOI2008]玩具装箱TOY

代码实现:

//Optimize
#pragma GCC optimize("Ofast")

//Head File
#include<bits/stdc++.h>
using namespace std;

#define il inline

//Variable
#define ll long long
#define ull unsigned long long
#define db double
#define lb long double

//Debug
#define B cerr<<"Break Point"<<endl;
#define P(x) cerr<<#x<<' '<<"="<<' '<<(x)<<endl;
#define p(x) cerr<<#x<<' '<<"="<<' '<<(x)<<' ';
#define ml(x) cerr<<"Size of array is "<<x*4/1024/1024<<" MB"<<endl;

//Vector
#define vc vector
#define pub push_back
#define pob pop_back
#define vbe(x) x.begin(),x.end()

//Memset
#define ms(x) memset(x,0,sizeof(x))
#define MS(x) memset(x,0x3f3f3f3f,sizeof(x))

//Pair
#define fi first
#define se second

//File

#define fin(x) freopen(x,"r",stdin)
#define fou(x) freopen(x,"w",stdout)
void fio()
{
    #ifndef ONLINE_JUDGE
    freopen("sample.in","r",stdin);
    freopen("sample.out","w",stdout);
    #endif
}
void pti()
{
    double timeuse = clock()*1000.0/CLOCKS_PER_SEC;
    cerr<<"Timeuse "<<timeuse<<"ms"<<endl;
}
void end()
{
    pti();
    exit(0);
}

//Inf
#define INF 0x3f3f3f3f
#define LINF ((long long)(0x3f3f3f3f3f3f3f3f))

//IO
namespace io
{
	const int SIZ=55;int que[SIZ],op,qr;char ch;
	template<class I>
	il void gi(I &w)
    {
        ch=getchar(),op=1,w=0;while(!isdigit(ch)){if(ch=='-') op=-1;ch=getchar();}
        while(isdigit(ch)){w=w*10+ch-'0';ch=getchar();}w*=op;
    }
	template<class I>
	il void print(I w)
    {
        qr=0;if(!w) putchar('0');if(w<0) putchar('-'),w=-w;while(w) que[++qr]=w%10+'0',w/=10;
        while(qr) putchar(que[qr--]);
    }
}
using io::gi;
using io::print;

const int N=5e4+5;

int n,m;

struct land
{
    int a,b;
    bool operator<(const land &x)const
    {
        if(a==x.a) return b>x.b;
        return a>x.a;
    }
};

ll f[N];
int top,stk[N],anc[N];
land c[N],t[N];

ll calc(int x,int y)
{
    return f[x]+1ll*t[x+1].a*t[y].b;
}
int find(int x)
{
    int l=stk[top],r=m;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(calc(x,mid)>=calc(anc[top],mid)) l=mid+1;
        else r=mid-1;
    }
    return l;
}
int main()
{
    fio();
    gi(n);
    for(int i=1;i<=n;++i) gi(c[i].a),gi(c[i].b);
    sort(c+1,c+n+1);
    ll maxv=-1;
    for(int i=1;i<=n;++i) if(c[i].b>maxv) maxv=c[i].b,t[++m]=c[i];
    int cur=1;
    stk[++top]=1;
    for(int i=1;i<=m;++i)
    {
        if(i==stk[cur+1]&&cur<top) ++cur;
        f[i]=calc(anc[cur],i);
        while(top>0&&calc(i,stk[top])<=calc(anc[top],stk[top])) --top;
        int pos=find(i);
        if(pos<=m) stk[++top]=pos,anc[top]=i;
    }
    print(f[m]);
    end();
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!