题目链接
Codeforces Round 872 (Div. 2)
Example
input
5
2 2
1 3 1 4
2 2
-1 -1 -1 -1
2 3
7 8 9 -3 10 8
3 2
4 8 -3 0 -7 1
4 3
-32030 59554 16854 -85927 68060 -64460 -79547 90932 85063 82703 -12001 38762
output
9
0
64
71
1933711
题目大意:
每组测试给一个n和m,随后给出nm个数。
要求将这些数放进nm的矩阵数组中,求上述式子的最大值。
其实每次都是取矩阵(1,1)到(i,j)这个子矩阵中最大值和最小值,将最大值减去最小值即可,最后将所有的值相加。
解题思路:
因为数字放的位置不同,最后的结果可能会有变化,但会注意到每次是取矩阵中的最大值和最小值,那么就分两种情况:
1.最大值只有一个,那么最大值就应该放在(1,1)的位置,然后取max(n,m),如果行数比列数大,那么最小值就放在(2,1)的位置,否则放在(1,2)的位置,然后第二小的值放在(2,1)/(1,2)剩下的位置
2.最小值只有一个,其实情况和最大值一样,至是一开始是最小值放在(1,1)的位置!
将两种情况取最大值即可
这里简单推到一下,因为是取矩阵的最大值和最小值,如果最大值和最小值已经在蓝色和红色的区域,那么剩下的值就会被随机放在其他位置。但会发现,绿色区域的值,永远都是数组b里面最大值-最小值。
这是情况1最大值只有1,而且列数比行数多,也就是说红色区域比蓝色区域大,那么最小值会放在(1,2),如果随机取i,j,也就是紫色区域,那么从(0,0)到(i,j)的矩阵就是红蓝和橙色圈起来的,会发现该矩阵一定会包含最大值和最小值。证明结束。
反证(证明为什么如果列数比行数多,小一放在(1,2)):如果小一不放在(1,2),那么(1,2)这个子矩阵的值是 最大值-n=ans1,如果是小一放在里面 ans2=最大值-小一,明显ans1<ans2,如果小一越“远离”(1,1)那么将会有更多的子矩阵的值比该方法小。而为什么不放(2,1)原因很简单,如下图,如果放在(1,2)将会有3个子矩阵是最大值,而放在(1,2)只有2个子矩阵是最大值!
C++
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int N = 101 * 101 +101;
int a[N];
signed main(void){int t;cin>>t;while(t--){int n,m;cin>>n>>m;for(int i=0;i<n*m;i++){scanf("%lld",&a[i]);}sort(a,a+n*m);int minans=a[0];int minans2=a[1];int maxans=a[n*m-1];int maxans2=a[n*m-2];int maxnm=max(n,m);int minnm=min(n,m);int ans=(maxnm-1)*(maxans-minans)+(minnm-1)*(maxans2-minans)+(n*m-n-m+1)*(maxans-minans);int ans2=(maxnm-1)*(maxans-minans)+(minnm-1)*(maxans-minans2)+(n*m-n-m+1)*(maxans-minans);cout<<max(ans,ans2)<<endl;}return 0;
}
C语言
#include <stdio.h>
#include <limits.h>
#define int long long
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a>b?b:a;}
signed main(void){int t;scanf("%lld",&t);while(t--){int n,m;scanf("%lld%lld",&n,&m);int minans=LLONG_MAX;int minans2=LLONG_MAX;int maxans=LLONG_MIN;int maxans2=LLONG_MIN;int maxnm=max(n,m);int minnm=min(n,m);for(int i=0;i<n*m;i++){int num;scanf("%lld",&num);if(maxans<=num) {maxans2= maxans;maxans = num;}else if(maxans2<=num)maxans2= num;if(minans>=num) {minans2=minans;minans = num;}else if(minans2>=num)minans2=num;}int ans=(maxnm-1)*(maxans-minans)+(minnm-1)*(maxans2-minans)+(n*m-n-m+1)*(maxans-minans);int ans2=(maxnm-1)*(maxans-minans)+(minnm-1)*(maxans-minans2)+(n*m-n-m+1)*(maxans-minans);printf("%lld\n",max(ans,ans2));}return 0;
}