题目
题目大意
给出分别有 N , M N,M N,M个元素的序列 a , b a,b a,b,定义一个乘积矩阵,其中的元素 c i , j = a i × b j c_{i,j}=a_i\times b_j ci,j=ai×bj,找到它的一个最大面积子矩阵,使得这个子矩阵的元素之和不大于给定的 X X X。所有数都是正数, N , M ≤ 2000 N,M\leq 2000 N,M≤2000。
思路
比赛的时候第一次
15
15
15分钟内切掉前
2
2
2题,剧烈膨胀,结果大脑抽筋死在第
3
3
3题。
设这个矩阵左上角为
c
i
1
,
j
1
c_{i_1,j_1}
ci1,j1,右下角为
c
i
2
,
j
2
c_{i_2,j_2}
ci2,j2,那么它的元素之和为:
∑
i
=
i
1
i
2
∑
j
=
j
1
j
2
a
i
×
b
j
\sum\limits_{i=i_1}^{i_2}\sum\limits_{j=j_1}^{j_2}a_i\times b_j
i=i1∑i2j=j1∑j2ai×bj
化简一下得:
∑
i
=
i
1
i
2
a
i
∑
j
=
j
1
j
2
b
j
\sum\limits_{i=i_1}^{i_2}a_i\sum\limits_{j=j_1}^{j_2}b_j
i=i1∑i2aij=j1∑j2bj
记录一下
a
,
b
a,b
a,b的前缀和记为
s
u
m
a
,
s
u
m
b
sum_a,sum_b
suma,sumb,于是得到:
(
s
u
m
a
[
i
2
]
−
s
u
m
a
[
i
1
−
1
]
)
×
(
s
u
m
b
[
j
2
]
−
s
u
m
b
[
j
2
−
1
]
)
≤
X
(sum_a[i_2]-sum_a[i_1-1])\times(sum_b[j_2]-sum_b[j_2-1])\leq X
(suma[i2]−suma[i1−1])×(sumb[j2]−sumb[j2−1])≤X
相当于是从
a
,
b
a,b
a,b中分别找一段元素之和乘起来不大于
X
X
X。
以上内容是比赛时想到的。
然后先想了个
O
(
l
o
g
N
l
o
g
M
⋅
N
M
)
O(logNlogM·NM)
O(logNlogM⋅NM),写着写着发现是错的。
然后想了个用set
乱搞
O
(
(
l
o
g
N
+
l
o
g
M
)
N
M
)
O((logN+logM)NM)
O((logN+logM)NM)的,交上去只过了样例,WA
了三次后发现思路还是错的。
我直到比赛结束都觉得是个二分搜索。
于是我颓废了。
接下来是正解。
可以用
O
(
N
2
)
O(N^2)
O(N2)和
O
(
M
2
)
O(M^2)
O(M2)时间处理出
a
,
b
a,b
a,b中长度为len
的一段区间的最小元素和
S
a
[
l
e
n
]
,
S
b
[
l
e
n
]
S_a[len],S_b[len]
Sa[len],Sb[len]。
然后再用 O ( N M ) O(NM) O(NM)枚举从 a a a中选长度为 i i i, b b b中选长度为 j j j的一段,它们乘积之和最小为 S a [ i ] × S b [ j ] S_a[i]\times S_b[j] Sa[i]×Sb[j],如果这个值不大于 X X X,说明可以,就更新答案。
我突然觉得自己不够贪心啊= =
代码
早上起来赶的,写得丑不要介意。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 2000
#define LL long long
int N[2],X,Ans;
LL Sum[2][MAXN+5],MinSum[3][MAXN+5];
int main(){
scanf("%d%d",&N[0],&N[1]);
for(int i=0;i<=1;i++)
for(int j=1;j<=N[i];j++){
int t;scanf("%d",&t);
Sum[i][j]=Sum[i][j-1]+t;
}
scanf("%d",&X);
memset(MinSum,0x7f,sizeof MinSum);
for(int i=0;i<=1;i++)
for(int len=1;len<=N[i];len++)
for(int j=len;j<=N[i];j++)
MinSum[i][len]=min(MinSum[i][len],Sum[i][j]-Sum[i][j-len]);
for(int i=1;i<=N[0];i++)
for(int j=1;j<=N[1];j++)
if(MinSum[0][i]*MinSum[1][j]<=X)
Ans=max(Ans,i*j);
printf("%d",Ans);
}