• [USACO19FEB]Mowing Mischief


    题目大意:

    给定平面上的一些点,求这些点的一个(LIS),并且还需要满足下列式子最小:

    [sum_{i=1}^{n-1}(a[i+1].x-a[i].x)*(a[i+1].y-a[i].y) ]

    题解:

    比较巧妙的一道题。

    首先我们需要找出一个性质,我们先令(dp[i])表示以(i)点结尾的(LIS),然后这些(LIS)相同的点在平面上是横坐标递增,纵坐标递减的,下面我们说的转移点的顺序都是按照这个顺序来的。

    然后我们在观察转移,我们令两个转移点(j)(k),若(k)(j)更优,那么有:

    [dp[k]+(a[i].x-a[k].x)*(a[i].y-a[k].y)geq dp[j]+(a[i].x-a[j].x)*(a[i].y-a[j].y) ]

    [a[i].x*(a[j].y-a[k].y)+a[i].y*(a[j].x-a[k].x)geq dp[j]-dp[k]+a[j].x*a[j].y-a[k].x*a[k].y ]

    [A*a[i].x+B*a[i].ygeq C ]

    可以看出,这其实是一个半平面,结合上面的性质,对于一排待转移点,更优的转移是一段前缀或者一段后缀,这启发我们这道题中有决策单调性。

    但是这个东西还有一个条件就是(a[i].xgeq a[j].x a[i].ygeq a[j].y),这个东西其实我们发现合法的转移点也是一段连续的区间,这启发我们在外面线段树分治解决这个限制。

    对于决策单调性的部分,我们可以令(k)(j)的后面一个点,那么上面的(A)是负的(B)是正的,所以合法的区域在直线上方,按照这个做决策单调性就好了。

    代码

    #include<bits/stdc++.h>
    #define M 1000009
    #define N 200009
    using namespace std;
    typedef long long ll;
    vector<int>vec[N],now;
    vector<int>::iterator it;
    int n,T,dp[N];
    ll f[N],ans;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    struct BIT{
    	int tr[M];
    	inline void add(int x,int y){
    		while(x<=T)tr[x]=max(tr[x],y),x+=x&-x;
    	}
    	inline int query(int x){
    	    int ans=0;
    	    while(x)ans=max(ans,tr[x]),x-=x&-x;
    	    return ans;
    	}
    }T1;
    struct point{
    	int x,y;
    	inline bool operator <(const point &b)const{
    		if(x!=b.x)return x<b.x;
    		else return y<b.y;
    	}
    }a[N];
    struct seg{
    	#define ls tr[cnt].l
    	#define rs tr[cnt].r
    	int rot,tott;
    	struct node{
    		int l,r;
    		vector<int>nw;
        }tr[N<<1];
        void build(int &cnt,int l,int r){
        	cnt=++tott;tr[cnt].l=tr[cnt].r=0;
        	tr[cnt].nw.clear();
        	if(l==r)return;
        	int mid=(l+r)>>1; 
        	build(ls,l,mid);build(rs,mid+1,r);
    	}
        inline void init(){
        	tott=0;
        	build(rot,0,now.size()-1);
    	}
    	inline void upd(int cnt,int l,int r,int id){
    		if(a[id].x>=a[now[r]].x&&a[id].y>=a[now[l]].y){
    			tr[cnt].nw.push_back(id);
    			return;
    		}
    		if(a[id].x<a[now[l]].x||a[id].y<a[now[r]].y)return;
    		if(l==r)return;
    		int mid=(l+r)>>1;
    		upd(ls,l,mid,id);upd(rs,mid+1,r,id);
    	}
    	inline void _upd(int tag,int l,int r,int L,int R){
    		if(l>r)return; 
    		int no=tr[tag].nw[(l+r)>>1];
    		ll biu=1e18,tg=0;
    		for(int i=L;i<=R;++i){
    			int id=now[i];
    			ll x=f[id]+1ll*(a[no].x-a[id].x)*(a[no].y-a[id].y);
    			if(x<biu){
    				biu=x;
    				tg=i;
    			}
    		}
    		f[no]=min(f[no],biu);
    		int mid=(l+r)>>1;
    		_upd(tag,l,mid-1,tg,R);
    		_upd(tag,mid+1,r,L,tg);
    	} 
    	inline void work(int id){
    		upd(rot,0,now.size()-1,id);
    	}
    	void solve(int cnt,int l,int r){
    		_upd(cnt,0,tr[cnt].nw.size()-1,l,r);
    		if(l==r)return;
    		int mid=(l+r)>>1;
    		solve(ls,l,mid);solve(rs,mid+1,r);
    	}
    	inline void solve(){
    		solve(rot,0,now.size()-1);
    	}
    	#undef ls
    	#undef rs
    }T2;
    int main(){
    	n=rd();T=rd();
    	for(int i=1;i<=n;++i){
    		a[i].x=rd();a[i].y=rd();
    	}
    	sort(a+1,a+n+1);
    	int maxx=0;
    	for(int i=1;i<=n;++i){
    		dp[i]=T1.query(a[i].y)+1;
    		T1.add(a[i].y,dp[i]);
    		vec[dp[i]].push_back(i);
    		maxx=max(maxx,dp[i]);
    	}
    	memset(f,0x3f,sizeof(f));
    	for(it=vec[1].begin();it!=vec[1].end();++it){
    		int x=*it;
    		f[x]=1ll*a[x].x*a[x].y;
    	}
    	for(int i=2;i<=maxx;++i){
    		now=vec[i-1];
    		T2.init();
    		for(it=vec[i].begin();it!=vec[i].end();++it){
    			int x=*it;
    			T2.work(x);
    		}
    		T2.solve();
    	}
    	ans=1e18;
    	for(it=vec[maxx].begin();it!=vec[maxx].end();++it){
    		int x=*it;
    		ans=min(ans,f[x]+1ll*(T-a[x].x)*(T-a[x].y));
    	}
    	cout<<ans; 
    	return 0;
    }
    
  • 相关阅读:
    php && 逻辑与运算符使用说明
    php无穷递归算法
    PHP foreach 用法
    centos安装g++
    php 编译中apxs
    shutdown()
    C语言strtok()函数:字符串分割
    细谈select函数(C语言)
    setsockopt的作用
    STL之七:STL各种容器的使用时机详解
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10788443.html
Copyright © 2020-2023  润新知