題目鏈接:點擊查看
題目大意:在二維平面中給出 n 個點可以作為矩形左下角的點,再給出 m 個點可以作為矩形右上角的點,現在問最大可以構造出多大面積的矩形,即如何選擇,可以使得 ( b[ j ] . x?- a[ i ] . x ) * ( b[ j ] . y - a[ i ] . y ) 最大
題目分析:首先貪心去想,對于矩形左下角的點來說,如果存在著兩個點 A( x1 , y1 ),B( x2 , y2 ),滿足 x1 < y1 且 x2 < y2 的話,那么點 A 一定是要比點 B 永遠都是更優的,所以可以直接把點 B 刪除掉,對于矩形右上角的點也是同理,這個操作在預處理時線性遍歷一遍就可以完成,貪心完成后剩余的點應該如下圖所示:
如果用圖示畫出來的話,應該往斜率優化dp或者決策單調性方面去想,因為是二維的點,斜率優化的話需要三維凸包,所以考慮決策單調性
簡單來說就是,設數組 a 是左下角的點,數組 b 是右下角的點,如果 a[ i ] 和 b[ j ] 是最優的,也就是 a[ i ] 和 b[ j - 1 ] 不是最優的,那么 a[ i + 1 ] 一定不可能和 b[ j - 1 ] 是最優的,證明如下:
所以不難看出,最后的化簡的公式與假設相悖,所以得證
如此一來就可以分治去解決了,具體策略如下:設 solve( l1 , r1 , l2 , r2 ) 為當前區間的詢問區間為 [ l1 , r1 ] ,決策所在區間為 [ l2 , r2 ] 時的最優答案,即 [ l1 , r1 ] 對應的是數組 a,[ l2 , r2 ] 對應的是數組 b,每次選擇詢問區間的中位數去決策區間中尋找最優決策設為 pos,根據決策單調性不難看出,[ l1 , mid - 1 ] 的決策只可能在 [ l1 , pos ] 中出現,同理 [ mid + 1 , r1 ] 的決策只可能在 [ pos , r2 ] 中出現,如此遞歸下去時間復雜度是 O( nlogn ) 級別的
有一點小細節就是,有可能決策為負數,或者 a 變成了矩陣的右上角端點,b 變成了矩陣的左下角端點,此時的決策應該是負無窮(不應該出現這種情況),雖然決策為負數時無法更新答案,但是卻可以更新相對的最優情況,如此分治下去肯定是最優的
代碼:
?
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const LL inf=0x3f3f3f3f3f3f3f3f;const int N=1e6+100;int n,m;bool ban[N];struct Node
{LL x,y;void input(){scanf("%lld%lld",&x,&y);}bool operator<(const Node& t)const{if(x!=t.x)return x<t.x;return y<t.y;}
}a[N],b[N];void init_a()
{sort(a+1,a+1+n);memset(ban,false,sizeof(ban));int last=1;for(int i=2;i<=n;i++){if(a[i].y>=a[last].y)ban[i]=true;elselast=i;}int tot=0;for(int i=1;i<=n;i++)if(!ban[i])a[++tot]=a[i];n=tot;
}void init_b()
{sort(b+1,b+1+m);memset(ban,false,sizeof(ban));int last=m;for(int i=m-1;i>=1;i--){if(b[i].y<=b[last].y)ban[i]=true;elselast=i;}int tot=0;for(int i=1;i<=m;i++)if(!ban[i])b[++tot]=b[i];m=tot;
}LL cal(int i,int j)
{if(b[j].x<a[i].x&&b[j].y<a[i].y)return -inf;return (b[j].x-a[i].x)*(b[j].y-a[i].y);
}LL solve(int l1,int r1,int l2,int r2)//a[l1,r1],b[l2,r2]
{if(l1>r1||l2>r2)return 0;int mid=l1+r1>>1;int pos=l2;for(int i=l2+1;i<=r2;i++)if(cal(mid,pos)<cal(mid,i))pos=i;return max({solve(l1,mid-1,l2,pos),solve(mid+1,r1,pos,r2),cal(mid,pos)});
}int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.ans.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)a[i].input();for(int i=1;i<=m;i++)b[i].input();init_a();init_b();printf("%lld\n",solve(1,n,1,m));return 0;
}
?
總結
以上是生活随笔為你收集整理的Gym - 101471D Money for Nothing(决策单调性+分治+贪心)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。