题意:有一堆木棒,每根木棒有一个长度l,每根木棒可以砍掉1个单位长度变成l - 1,用这些木棒拼成矩形,使得拼成的矩形面积最大,问最多能拼成的矩形面积的总和。
基本思路:由于拼成矩形至少需要两对长度相同的对边,那么让每个长度出现的次数尽可能为偶数,然后从大到小两两相乘累加即可。
注意:若长度出现次数是如下情况:
长度 次数
345 2
344 2
343 1
342 2
341 4
340 1
339 6
338 4
则长度为340的木棒不能直接扔掉,可以将343减1给342,342拿出2根木棒中的一根减1给341,341拿出4根木棒中的一根减1给340,那么340出现的次数也将变成偶数!!!
// Ilya and Sticks.cpp
#include <bits/stdc++.h>
#define LL long long
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define PI 3.1415926535897932626
#define EXIT exit(0);
#define PAUSE system("pause");
#define DEBUG puts("Here is a BUG");
#define SYNC_CLOSE ios::sync_with_stdio(false);
#define what_is(x) cerr << #x << " is " << x << endl;
#define CLEAR(name, init) memset(name, init, sizeof(name));
const double eps = 1e-8;
const int MAXN = (int)1e6 + 5;
using namespace std;
int m[MAXN];
bool vis[MAXN];
std::vector<LL> res;
int main(int argc, char const *argv[]) {
#ifndef ONLINE_JUDGE
freopen("D:\\Documents\\Disk_Synchronous\\Programs\\Acm\\input.txt", "r", stdin);
#endif
int n; cin >> n;
CLEAR(m, 0); CLEAR(vis, 0);
while(n--) {
int tmp; cin >> tmp;
m[tmp]++;
}
for(int i = MAXN-1; i > 0; i--) {
if (m[i] == 0) continue;
if (m[i] % 2 == 0) {
if (vis[i]) { // 若i长度木棒出现次数为偶数并且i+1长度的木棒可以传给i一根木棒,则i木棒可以拿出自身一根木棒传递给i-1长度的木棒,并用i+1传给i的木棒来弥补自身空缺
vis[i] = false;
vis[i-1] = true;
}
}
else { // 若i长度木棒出现次数为奇数
if (vis[i]) m[i]++; // 若i+1长度的木棒可以传给i一根木棒,则i长度木棒可以获得这跟木棒来凑成偶数
else {
m[i]--; // 反之当前木棒可以舍弃一根木棒用于传递给i-1长度的木棒
vis[i-1] = true;
}
}
}
for(int i = 0; i < MAXN; i++) {
for(int j = 0; j < (m[i]>>1); j++) {
res.push_back(i); // 这些木棒所能构成的边的最大对数
}
}
sort(res.rbegin(), res.rend()); // 从大到小排序
if (res.size() > 1) {
LL ans = 0;
int n = res.size();
for(int i = 0; i < n-1; i += 2) {
ans += res[i] * res[i+1];
}
cout << ans << endl;
}
else puts("0");
return 0;
}