一道很好的构造题
原题链接
很快就能想到,捡每个垃圾的能量可以最后再算。然后,对于每个垃圾,在路上耗费的能量仅与它是第几个被捡的有关,于是我们考虑将垃圾分组。
首先,我们定义\(F(x,i)\)为某次从\(0\)出发,捡到坐标为\(x\)的垃圾的次序为\(i\)的花费,则有:
由上式,易知对于每一组,让机器人先捡最右边的垃圾,然后往回一个一个捡是最优的。同时,将所有垃圾从后往前按一个固定的间隔\(k\)分组是最优的。
所以,我们只需要枚举\(k\),再利用前缀和,\(O(logn)\)计算组间距为\(k\)的花费,更新一下答案就行了。
为什么是\(O(logn)\)?因为调和级数的性质,\(\sum\limits_{i=1}^n\frac{1}{i}=logn+O(1)\)。
因为中途计算时可能会爆\(long long\),所以我们要特判一下,当前的花费大于等于\(ans\)时就可以跳出循环了。
Code:
#include <bits/stdc++.h>using namespace std;#define ll long longint n;
ll x, ans = (ll)9e18, a[200005];int main() {cin >> n >> x;for(int i = 1; i <= n; ++i) cin >> a[i], a[i] += a[i-1];for(int k = 1; k <= n; ++k) {ll coef = 3LL, sum = 0;for(int i = n; i >= 1; i -= k) {sum += (a[i]-a[max(0, i-k)])*max(coef, 5LL), coef += 2;if(sum >= ans) break; //防爆long long}ans = min(ans, sum+(k+n)*x);}cout << ans << endl;return 0;
}