Maximum Subrectangle(CodeForces-1060C#513)(預處理優化暴力)
阿新 • • 發佈:2018-12-13
前言
打的時候開始寫了的二分,調了半天…還是沒過,然後發現直接預處理暴力就過了…
題目
題目大意:
現在你有一個長度為n的序列A,長度為m的序列B,和一個數x,然後A·B得到一個n*m的矩陣C,現在讓你選擇滿足 的條件下讓矩形面積最大,求出矩形面積最大值 直白翻譯:框出一個子矩形讓矩形內權值和小於x的前提下面積最大
資料範圍
思路
溫馨提示:作者會從無腦暴力到有腦暴力
這是小白的做法…處理出C,暴力列舉要選矩形的左上角和右下角,然後掃一遍內部元素,判斷是否合法,ans不斷更新…
我們其實可以發現 : 那麼我們記為a陣列的字首和,為b陣列的字首和,顯然又有:
我們又可以發現當我們確定矩形的右下角和一條邊長,另一條邊其實可以二分找出來的如果第一條邊是列舉的i則: 判斷與x大小關係二分就可以了
這就可以過題了,我們剛剛列舉的必須確定一個點,但我們可以換一下思路,我們列舉兩條平行的邊,假設我們列舉B,記,這已經是了,那麼在A中的兩個端點(記為l,r)則有 發現右邊可以提前算出來… 那我們就可以預處理出存在一個數組中,同時記錄一下那麼我們就可以二分找出答案了, 注意我們的目的要儘量地大,我們還要將較小的差值但較大的長度傳給較大差值的數。然後照常記錄答案就可以了
程式碼
#include<set>
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int read(){
int f=1,x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
#define MAXN 2000
#define INF 0x3f3f3f3f
#define Mod int(1e9+7)
int n,m;
struct node{
LL val,l;
friend bool operator < (node a,node b){return a.val<b.val;}//排序規則
}Map[MAXN*MAXN+5];
LL a[MAXN+5],b[MAXN+5],s1[MAXN+5],s2[MAXN+5];
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read(),s1[i]=s1[i-1]+a[i];
for(int i=1;i<=m;i++)
b[i]=read(),s2[i]=s2[i-1]+b[i];
LL x=read(),len=0,ans=0;
for(int i=1;i<=m;i++)
for(int j=i;j<=m;j++)//預處理出B
Map[len].l=j-i+1,Map[len++].val=s2[j]-s2[i-1];
sort(Map,Map+len);
for(int i=1;i<len;i++)
Map[i].l=max(Map[i].l,Map[i-1].l);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++){
LL S=s1[j]-s1[i-1],sum=x/S;
if(!sum) continue;
LL L=0,R=len,mid;
while(L+1<R){//二分找答案
mid=(L+R)>>1;
if(Map[mid].val<=sum) L=mid;
else R=mid;
}
if(Map[L].val>sum) continue;
ans=max(ans,Map[L].l*(j-i+1));
}
printf("%l