原题链接: https://codeforces.com/contest/2000/problem/E
一道非常非常非常有意思的题目
题目大意:
有一个 n * m 的格子图,每个格子是 1 * 1 的大小,每个格子里最多只能站一只大猩猩,一共有g只大猩猩,告诉你每只大猩猩的身高 。包围区的大小是一个 k * k 的大格子,求的是每个包围区内大猩猩高度的总和,求的是这个总和的最大值。
对于题目对于第一个样例的解释,给出了一张图:
那么我们来对这个样例一进行深度解析,让我们来算算每只大猩猩分别被加了几次身高,显而易见的,要使得总和最大,那么最高的大猩猩肯定要它站加的最多的地方。
我们把这些数字放进一个一维数组并从大往小排序就会得到一个这样的数组:
4,4,2,2,2,2,2,2,1,1,1,1
对于这个数组对应着每个大猩猩需要加的次数,那么非常明显了,我们再使大猩猩的身高也按照从高到低排序,然后按照这个顺序依次相乘并相加就可以了。
那么第二个问题来了,如何去绘制这个表格呢。那么就要更大的样例来找出这个关系式子了。
在一个 6 * 8 的格子图中我们令 k = 3 ,可以得到以下的图:
从中我们可以知道,只要算出上边和左边即可,剩下的直接用乘法填入表格即可。
不过填表时需要注意以下的这种情况:
剩下的就是分别排序然后乘起来加起来即可,直接上代码:
#include<bits/stdc++.h>
using namespace std;
int t,n,m,k,g;
bool cmp(long long x,long long y){
return x > y;
}
void solve(){
long long num = 0;
cin>>n>>m>>k>>g;
vector <vector <int> > gezi(n,vector <int> (m));
vector <long long> a(g);
vector <long long> zhi;
for(int i=0;i<g;i++) cin>>a[i];
sort(a.begin(),a.end(),cmp);
int henb = min(k,m-k+1),shub = min(k,n-k+1);
int tap = 1;
for(int i=0;i<m/2;i++){
gezi[0][i] = tap;
gezi[0][m-1-i] = tap;
tap++;
if(tap > henb) tap = henb;
}
if(m%2 == 1) gezi[0][m/2] = tap;
tap = 1;
for(int i=0;i<n/2;i++){
gezi[i][0] = tap;
gezi[n-1-i][0] = tap;
tap++;
if(tap > shub) tap = shub;
}
if(n%2 == 1) gezi[n/2][0] = tap;
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
gezi[i][j] = gezi[0][j] * gezi[i][0];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
zhi.push_back(gezi[i][j]);
sort(zhi.begin(),zhi.end(),cmp);
for(int i=0;i<g;i++)
num += zhi[i] * a[i];
cout<<num<<endl;
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>t;
while(t--) solve();
return 0;
}