CF513C Maximum Subrectangle

版权声明:本文为博主原创文章,不管你喜不喜欢都请在注明作者后转载~( ̄▽ ̄~) https://blog.csdn.net/C20190102/article/details/82942156

题目

传送门

题目大意

给出分别有 N , M N,M 个元素的序列 a , b a,b ,定义一个乘积矩阵,其中的元素 c i , j = a i × b j c_{i,j}=a_i\times b_j ,找到它的一个最大面积子矩阵,使得这个子矩阵的元素之和不大于给定的 X X 。所有数都是正数, N , M 2000 N,M\leq 2000

思路

比赛的时候第一次 15 15 分钟内切掉前 2 2 题,剧烈膨胀,结果大脑抽筋死在第 3 3 题。
设这个矩阵左上角为 c i 1 , j 1 c_{i_1,j_1} ,右下角为 c i 2 , j 2 c_{i_2,j_2} ,那么它的元素之和为: 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 = 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
记录一下 a , b a,b 的前缀和记为 s u m a , s u m b sum_a,sum_b ,于是得到: ( 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
相当于是从 a , b a,b 中分别找一段元素之和乘起来不大于 X X


以上内容是比赛时想到的。
然后先想了个 O ( l o g N l o g M N M ) O(logNlogM·NM) ,写着写着发现是错的。
然后想了个用set乱搞 O ( ( l o g N + l o g M ) N M ) O((logN+logM)NM) 的,交上去只过了样例,WA了三次后发现思路还是错的。

我直到比赛结束都觉得是个二分搜索。
于是我颓废了。


接下来是正解。
可以用 O ( N 2 ) O(N^2) O ( M 2 ) O(M^2) 时间处理出 a , b a,b 长度为len的一段区间的最小元素和 S a [ l e n ] , S b [ l e n ] S_a[len],S_b[len]

然后再用 O ( N M ) O(NM) 枚举从 a a 中选长度为 i i b b 中选长度为 j j 的一段,它们乘积之和最小为 S a [ i ] × S b [ j ] S_a[i]\times S_b[j] ,如果这个值不大于 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);
}

猜你喜欢

转载自blog.csdn.net/C20190102/article/details/82942156