Photoshoot for Gorillas
Photoshoot for Gorillas
题面翻译
题目描述
你非常喜欢大猩猩,于是你决定为它们组织一次拍摄活动。大猩猩生活在丛林中,丛林被表示为一个有
每种方案的壮观程度等于网格中所有以
子正方形的壮观程度等于其中所有大猩猩的身高的总和。
从所有合适的方案中选出最壮观的方案。
输入格式
第一行包含一个整数
测试用例的描述如下。
第一行包含三个整数
第二行包含一个整数
第三行包含
保证所有测试样例中
输出格式
对于每个测试用例,输出一个整数表示最壮观的方案的壮观程度。
样例 #1
样例输入 #1
5
3 4 2
9
1 1 1 1 1 1 1 1 1
2 1 1
2
5 7
20 15 7
9
4 1 4 5 6 1 1000000000 898 777
1984 1 1
4
5 4 1499 2004
9 5 5
6
6 7 14 16 16 6
样例输出 #1
21
12
49000083104
3512
319
提示
在第一组输入数据的第一个测试用例里,要对如下子正方形的壮观程度进行求和:
黄色所对应的是这些子正方形,而绿色对应的是网格中其余的方格。图片展示的是大猩猩的最优排列方式。该排列方式的壮观程度为:
4 + 4 + 3 + 3 + 4 + 3 = 21 。
题解
本题中,壮观程度可以表示为
为得到 每个放个的重叠次数,可以将子方格在网格中遍历并利用 二维差分来将其遍历的方格的次数增加。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
void solve();
int main()
{
// 提高输入输出效率
ios::sync_with_stdio(false);
cin.tie(nullptr);
int _;cin >> _;
while(_--)
solve();
return 0;
}
void solve()
{
int n, m, k, w;
ll ans = 0;
// 输入网格的维度,子正方形的边长,大猩猩的数量
cin >> n >> m >> k >> w;
// 输入并将身高进行降序排序
vector<ll> a(w);
for(int i =0; i<w; i++)cin>>a[i];
sort(a.begin(), a.end(), greater<>());
// 使用差分数组方法记录 k * k 矩形区域的重叠次数
vector<vector<int>> p(n + 2, vector<int>(m + 2));
for (int i = 1; i + k - 1 <= n; i++) {
for (int j = 1; j + k - 1 <= m; j++) {
p[i][j] ++, p[i][j + k]--;
p[i + k][j] --, p[i + k][j + k]++;
}
}
// 利用前缀和计算每个位置的重叠次数,并存入d
vector<int> d;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
d.push_back(p[i][j] +=p[i - 1][j] + p[i][j - 1] - p[i - 1][j - 1]);
}
}
//将d降序排序
sort(d.begin(),d.end(), greater<>());
// 累加 重叠次数*身高
for (int i = 0; i<w; i++) ans += a[i] * d[i];
cout << ans << endl;
}