前缀和 + 贪心 - Combination of Physics and Maths - 2020牛客暑期多校训练营(第六场)

前缀和 + 贪心 - Combination of Physics and Maths - 2020牛客暑期多校训练营(第六场)

题意:

一个矩阵的底面积定义为最后一行的数的和,重量定义为所有数的和,

给一个正整数矩阵,找一个“压强” 最大的可非连续子矩阵。

输入:

T T组测试数据,

n m 每组包括两个正整数n和m,表示矩阵的行和列,

n m 接着输入一个n行m列的矩阵。

输出:

( ) 1 0 8 所有的子矩阵(可不连续)中,压强的最大值。输出误差不超过10^{-8}。

示例1
输入

1
3 3
1 3 5
6 8 9
2 7 4

输出

4.50000000

说明:

[ 1 5 6 9 2 4 ] 1 + 5 + 6 + 9 + 2 + 4 2 + 4 = 4.5 \begin{bmatrix}1&5\\6&9\\2&4\end{bmatrix}为所有子矩阵中,压强最大的,最大压强为:\frac{1+5+6+9+2+4}{2+4}=4.5

数据范围:

T 100 1 n , m 200 1 a i , j 5 1 0 4 T≤100,1≤n,m≤200,1≤a_{i,j​}≤5⋅10^4


分析:

i ①:假设选定某个底为第i行的子矩阵,那么该子矩阵在最优情况下,顶部一定是在第一行。

\qquad这就暗示我们,可能需要对矩阵的每一列预处理前缀和。

a 1 b 1 a 1 b 1 ②:假设当前已选择的某几列构成的子矩阵的重量为a_1,底面积为b_1,则压强为\frac{a_1}{b_1},

a 2 b 2 \qquad对于重量为a_2,底面积为b_2的列,

a 1 b 1 > a 2 b 2 a 1 b 1 > a 1 + a 2 b 1 + b 2 ( ) \qquad若有\frac{a_1}{b_1}>\frac{a_2}{b_2},则有\frac{a_1}{b_1}>\frac{a_1+a_2}{b_1+b_2},即不选择该列时,压强更大。(移项作差可证)

这样,对于每一行,我们计算出每一列的压强最大值,最后在所有最大值取一个最大值即可。

代码:

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N=210;

int T,n,m;
double a[N][N],sum[N][N];

int main()
{
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                sum[i][j]=0;
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%lf",&a[i][j]);
                
        for(int j=1;j<=m;j++)
            for(int i=1;i<=n;i++)
                sum[i][j]=sum[i-1][j]+a[i][j];
        
        double res=0;
        for(int i=1;i<=n;i++)
        {
            double maxb=0;
            for(int j=1;j<=m;j++) maxb=max(maxb,sum[i][j]/a[i][j]);
            res=max(res,maxb);
        }
        
        printf("%.8lf\n",res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/njuptACMcxk/article/details/107622264