现在给出一个长度为$N$的$a$数列,一个长度为$M$的$b$数列. 现在需要构造出一个矩阵$c$,其中$c_{i,j}=a_i imes b_j$.再给出一个$x$,请在矩阵中找出一个最大的矩形,使得这个矩形中的所有值的和小于等于$x$.
题解
刚开始打算上矩形里搞,然而突然想到如果是那样的话直接给出矩形就好了干嘛要有数列……
然后发现$sum_{i=x1}^{x2}sum_{j=y1}^{y2}c_{i,j}=sum_{i=x1}^{x2}sum_{j=y1}^{y2}a_i*b_j=sum_{i=x1}^x2a_i*sum_{j=y1}^{y2}b_j$
于是就变成两个数列选出两个区间的问题了……
然后因为数列很小,我们可以先枚举数列$b$,设$res[i]$表示$b$数列中长度为$i$的区间的最小值是多少,直接暴力预处理
然后枚举$a$的区间,因为对于同一个左端点来说,右端点右移的时候能匹配上的$b$的长度肯定是不升的,于是用指针记录一下就行了
复杂度$O(n^2)$
1 //minamoto 2 #include<bits/stdc++.h> 3 #define ll long long 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 9 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 10 inline int read(){ 11 #define num ch-'0' 12 char ch;bool flag=0;int res; 13 while(!isdigit(ch=getc())) 14 (ch=='-')&&(flag=true); 15 for(res=num;isdigit(ch=getc());res=res*10+num); 16 (flag)&&(res=-res); 17 #undef num 18 return res; 19 } 20 const int N=2005; 21 int a[N],b[N],suma[N],sumb[N],res[N],n,m,tot,ans=0,mn1=inf,mn2=inf; 22 void init(){ 23 memset(res,0x3f,sizeof(res)); 24 for(int i=1;i<=m;++i) 25 for(int j=i;j<=m;++j) 26 cmin(res[j-i+1],sumb[j]-sumb[i-1]); 27 } 28 int main(){ 29 // freopen("testdata.in","r",stdin); 30 n=read(),m=read(); 31 for(int i=1;i<=n;++i) 32 a[i]=read(),suma[i]=suma[i-1]+a[i],cmin(mn1,a[i]); 33 for(int i=1;i<=m;++i) 34 b[i]=read(),sumb[i]=sumb[i-1]+b[i],cmin(mn2,b[i]); 35 tot=read(); 36 if(mn1*mn2>tot) return puts("0"),0; 37 init(); 38 for(int i=1;i<=n;++i){ 39 int len=m; 40 for(int j=i;j<=n;++j){ 41 while(len&&1ll*res[len]*(suma[j]-suma[i-1])>tot) --len; 42 if(!len) break; 43 cmax(ans,len*(j-i+1)); 44 } 45 } 46 printf("%d ",ans); 47 return 0; 48 }