zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    dotnet core 获取 MacAddress 地址方法
    dotnet core 获取 MacAddress 地址方法
    dotnet core 发布只带必要的依赖文件
    dotnet core 发布只带必要的依赖文件
    Developing Universal Windows Apps 开发UWA应用 问答
    Developing Universal Windows Apps 开发UWA应用 问答
    cmd 如何跨驱动器移动文件夹
    cmd 如何跨驱动器移动文件夹
    C++ 驱动开发 error LNK2019
    C++ 驱动开发 error LNK2019
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10788443.html
Copyright © 2011-2022 走看看