50分思路
没什么好说的, 就十个测试点,看看前六个范围, 发现只要暴力跑一趟就能拿六十分,直接骗,后面的如果说要ac,性价比着实不高
具体思路:
一共 k * k 个座位,我们就将每行分为左右两边,每次只需要循环判断放哪一行的距离最小,
每次就尽量往中间放,可以保证每次是每行的最小距离(这里不做推导证明)
#include <bits/stdc++.h>
using namespace std;
typedef vector<bool> vi;
// L[i]表示第i行左半边,R则表示右半边
long long L[300005], R[300005];
//xc, yc 表示中中心坐标
long long xc, yc, n, k;
long long dis(int i, int x, int LR) {
long long res = 0;
//LR=1表示选左边座位,0表示右边座位
if (LR) {
if (L[i] < x) return 1e18;
//循环计算距离
for (int j = L[i] - x + 1; j <= L[i]; j++) res += abs(j - xc) + abs(i - yc);
} else {
if (R[i] < x) return 1e18;
//循环计算距离
for (int j = k - R[i] + 1; j <= k - R[i] + x; j++)
res += abs(j - xc) + abs(i - yc);
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
while (cin >> n >> k) {
xc = yc = k / 2 + 1;
for (int i = 1; i <= k; i++) L[i] = k / 2 + 1, R[i] = k / 2;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
long long res = 1e18, resL = 1e18, resR = 1e18, resI = 1e18;
for (long long j = 1; j <= k; j++) {
if (L[j] == k / 2 + 1 && R[j] == k / 2) {
//如果中间没有被用过,x就放中间,分奇偶讨论
//奇数直接放正中间,偶要往前放一个(自行推导证明
if (x & 1) {
long long disL = dis(j, x / 2 + 1, 1), disR = dis(j, x / 2, 0);
if (res > disL + disR) {
res = disL + disR, resI = j;
resL = L[j] - x / 2;
resR = xc + x / 2;
}
} else {
long long disL = dis(j, x / 2 + 1, 1), disR = dis(j, x / 2 - 1, 0);
if (res > disL + disR) {
res = disL + disR, resI = j;
resL = L[j] - x / 2;
resR = xc + x / 2 - 1;
}
}
} else {
//如果中间被占了,只能放在两边,直接判断即可
long long disL = dis(j, x, 1), disR = dis(j, x, 0);
if (res > disL) {
res = disL, resI = j;
resL = L[j] - x + 1;
resR = L[j];
}
if (res > disR) {
res = disR, resI = j;
resL = k - R[j] + 1;
resR = k - R[j] + x;
}
}
}
if (resI != 1e18) {
cout << resI << " " << resL << " " << resR << endl;
if (resL >= k / 2 + 2)
R[resI] -= x;
else if (resR <= k / 2 + 1)
L[resI] -= x;
else {
if (x & 1)
L[resI] -= x / 2 + 1, R[resI] -= x / 2;
else
L[resI] -= x / 2 + 1, R[resI] -= x / 2 - 1;
}
} else
cout << -1 << endl;
}
}
}
60分
long long dis(long long i, long long x, int LR) {
long long res = 0;
if (LR) {
if (L[i] < x) return 1e18;
else return abs(xc - L[i]) * x + (x - 1) * x / 2 + abs(i - yc) * x;
} else {
if (R[i] < x) return 1e18;
else return abs(xc - R[i]) * x + (x - 1) * x / 2 + abs(i - yc) * x;
}
return res;
}
可以推导50分处的dis函数可以直接用O(1)式子算出