Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) C. Maximum Subrectangle

昨天做的,今天才想起来,要写个博客,记一下这种矩阵题怎么做。

首先我没有意识到,每个方向上累和,得到两个累和数组,它们的子序列之积,就是子序列对应的矩形区域范围内所有数字之和,说起来有点抽象,但是举个栗子吧,

就像用例里面的这张提示图,横坐标我选子列2,3,则和为5,纵坐标我选子列1,2,则和为3。那么3和5,乘积为15,而把矩阵中对应区域的和相加,也是15,。则这个问题就容易了:只需要枚举一维数组就可以了。但是,如果枚举一维数组,那岂不是要做一个四重循环?其实不然。

题目要我们获得一个不大于限定数值的最大值,在此之前,我们需要对其中一个序列做一个预处理:二重循环枚举所有子列,计算对应子列长度下的最小子列和(最小,才能保证取更多的点,也就是更长的长度,也就是更大的面积)。之后,可以选定两个中的另一个序列,用一个二重循环得到子列和,再用限定数值除以这个和,得到一个目标值。之后,在最初预处理得到的数组中二分查找目标值,返回大于它的第一个值,也就是用upper_bound,求出之后长度减一即可,这样保证长度最长。最后,用查找得到的长度和当前子列长度相乘,得到的结果始终取最大值,循环结束之后,就是答案。

#include <bits/stdc++.h>
#define N 2005
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
int a[N],b[N];
ll ma[N],x;
int main()  {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,ans=0;
    fill(ma,ma+N,INF);
    cin>>n>>m;
    for (int i=1;i<=n;i++)  {cin>>a[i];a[i]=a[i-1]+a[i];}
    for (int i=1;i<=m;i++)  {cin>>b[i];b[i]=b[i-1]+b[i];}
    cin>>x;
    for (int i=1;i<=n;i++)  {
        for (int j=i;j<=n;j++)  {
            ll tsm=a[j]-a[i-1];
            int len=j-i+1;
            ma[len]=min(ma[len],tsm);
        }
    }
    for (int i=1;i<=m;i++)  {
        for (int j=i;j<=m;j++)  {
            ll sc=x/(b[j]-b[i-1]);
            int len=j-i+1;
            int mxa=upper_bound(ma+1,ma+n+1,sc)-ma-1;
            ans=max(ans,len*mxa);
        }
    }
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/yichuan-sun/p/9749030.html

时间: 2024-11-05 22:03:16

Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) C. Maximum Subrectangle的相关文章

[Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) ](A~E)

A: 题目大意:给你一个数字串,每个数字只可以用一次,求最多可以组成多少个电话号码(可以相同),电话号码第一个数字为$8$,且长度为$11$ 题解:限制为$8$的个数和总长度,直接求 卡点:无 C++ Code: #include <cstdio> #include <algorithm> #define maxn 1000 inline int min(int a, int b) {return a < b ? a : b;} inline int max(int a, i

Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2)

A.Phone Numbers 题意:给你n个数字,每个数字最多只能用一次,问你最多能组成以8开头的11位电话号码有多少个 思路:模拟即可,注意char数组读入是从0下标开始的(在这里被hack了...) 1 #include<bits/stdc++.h> 2 int main() 3 { 4 int n,num=0,ans=0; 5 char c[105]; 6 scanf("%d%s",&n,c); 7 for(int i=0;i<n;i++)if(c[i

Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) C D

C - Maximum Subrectangle 因为是两个数组相乘的到的 矩阵所以  a(i ->j)*b(x->y) 的面积 就是   a(i ->j) 的和乘与b(x->y)的和 所以我们枚举 a 序列 从1-n的长度和  B序列同理 然后 枚举两个序列和相乘 找一个最大即可 #include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define LL long long #defin

Codeforces Round #513 游记

Codeforces Round #513 游记 A - Phone Numbers 题目大意: 电话号码是8开头的\(1\)位数字.告诉你\(n(n\le100)\)个数字,每个数字至多使用一次.问最多能凑出多少个电话号码. 思路: 统计8出现的次数,如果有多余的8不能作为开头,那么就将其放到后面去 源代码: #include<cstdio> #include<cctype> #include<algorithm> inline int getint() { regi

Codeforces Round #513解题报告(A~E)By cellur925

我是比赛地址 A:Phone Numbers $Description$:给你一串数字,问你能组成多少开头为8的11位电话号码. $Sol$:统计8的数量,与$n$%11作比较. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,len,cnt,ans; 8 char ch[1000]; 9 10 int main() 11 {

Codeforces Round #513(Div.1+Div.2)

闲谈: 重新写博客的第一场比赛,感觉炸裂,成功被Rose和xgcD飞 A 题目: 给出一段长为n个数字字符串,求出能用里面的字符来构成多少个长度为11且开头字符为8的字符串 题解: 直接在n/11和8出现的数量中取min就可以了 参考代码: #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace

Codeforces Round #513 D - Social Circles(贪心)

题目大意: 有n(n≤105)个人排成一圈,第i个人要求自己左边空出li个座位,右边空出ri(li,ri≤109)个座位.问最少需要安排多少个座位.思路: 一开始先假设每个人都占了li+ri+1个位置.考虑怎样安排相邻人的顺序,并合并相邻人的li,ri使得答案最优.将所有li,ri分别排序,将对应的li,ri合并一定是最优的(想一想这是为什么). #include <iostream> #include <iomanip> #include <algorithm> #i

Educational Codeforces Round 36 (Rated for Div. 2)

Educational Codeforces Round 36 (Rated for Div. 2) F. Imbalance Value of a Tree You are given a tree T consisting of n vertices. A number is written on each vertex; the number written on vertex i is ai. Let's denote the function I(x,?y) as the differ

Educational Codeforces Round 36 (Rated for Div. 2) 题解

Educational Codeforces Round 36 (Rated for Div. 2) 题目的质量很不错(不看题解做不出来,笑 Codeforces 920C 题意 给定一个\(1\)到\(n\)组成的数组,只可以交换某些相邻的位置,问是否可以将数组调整为升序的 解题思路 首先如果每个数都能通过交换到它应该到的位置,那么就可以调整为升序的. 但实际上交换是对称的,如果应该在的位置在当前位置前方的数都交换完成,那么整体就是排好序的,因为不可能所有不在相应位置的数都在相应位置的后方.