4405. 统计子矩阵

给定一个 N×M𝑁×𝑀 的矩阵 A𝐴,请你统计有多少个子矩阵 (最小 1×11×1,最大 N×M𝑁×𝑀) 满足子矩阵中所有数的和不超过给定的整数 K𝐾?

输入格式

第一行包含三个整数 N,M𝑁,𝑀 和 K𝐾。

之后 N𝑁 行每行包含 M𝑀 个整数,代表矩阵 A𝐴。

输出格式

一个整数代表答案。

数据范围

对于 30%30% 的数据,N,M≤20𝑁,𝑀≤20,
对于 70%70% 的数据,N,M≤100𝑁,𝑀≤100,
对于 100%100% 的数据,1≤N,M≤500;0≤Aij≤1000;1≤K≤2.5×1081≤𝑁,𝑀≤500;0≤𝐴𝑖𝑗≤1000;1≤𝐾≤2.5×108。

输入样例:

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

输出样例:

19

样例解释

满足条件的子矩阵一共有 1919,包含:

  • 大小为 1×11×1 的有 1010 个。
  • 大小为 1×21×2 的有 33 个。
  • 大小为 1×31×3 的有 22 个。
  • 大小为 1×41×4 的有 11 个。
  • 大小为 2×12×1 的有 33 个。

暴力  O(N^4):

#include<bits/stdc++.h>

using namespace std;

const int N=510;

int m,n,k,s[N][N],a[N][N];

int main()
{
    cin >> m >> n >> k;
    for(int i=1;i<=m;i++)
     for(int j=1;j<=n;j++)
     {
         cin >> a[i][j];
         s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
     }
    long long int ans=0;
//四层循环,枚举每一个矩阵,并判断是否符合题解
    for (int x1 = 1; x1 <= m; x1 ++)
        for (int y1 = 1; y1 <= n; y1 ++)
            for (int x2 = x1; x2 <= m; x2 ++)
                for (int y2 = y1; y2 <= n; y2 ++) {
                    if (s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] <= k)
                    ans ++;
                }


    cout << ans;
    return 0;
}

优化O(n^3):

将左右两边放到一条线上,这时线上的长度就是矩阵的集合。类似于降维度

#include<bits/stdc++.h>

using namespace std;

const int N=510;

int m,n,k,s[N][N],a[N][N];

int main()
{
    cin >> m >> n >> k;
    for(int i=1;i<=m;i++)
     for(int j=1;j<=n;j++)
     {
         cin >> a[i][j];
         s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
     }
    long long int ans=0;
    //将左右边压缩成线性
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
        {
            //快指针t,慢指针s1
            for(int s1=1,t=1;t<=m;t++)
            {
                //当形成的矩阵大于目标值时,压缩矩阵的长度(s1++),当不大于k时,
                //就没必要压缩了,剩下的矩阵的值一定都小于k,符合的矩阵为:t-s1+1
                while(s1<=t&&s[s1-1][i-1]-s[t][i-1]-s[s1-1][j]+s[t][j]>k) s1++;
                //剩下t-s1+1个矩阵,因为是左右两边枚举向右扫值
                //所以不用担心后续的矩阵会少值的情况
                if(s1<=t) ans+=t-s1+1;
            }
        }
    }
    cout << ans;
    return 0;
}

当矩阵越来越大时,中间的矩阵如果符合题目要求,该怎么加上呢?

想多了,快指针与慢指针枚举过程中不会遗漏任何一个矩阵。

 

tips

先打暴力,之后再优化。

C++里只要数据次数少于1e8就能跑过。

本题明显只要优化一次就能跑过。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值