B - Garbage Collector
https://agc027.contest.atcoder.jp/tasks/agc027_b
题意:
x坐标轴上n个垃圾,有一个机器人在从原点,要清扫垃圾。原点有一个垃圾桶。机器人可以在x轴上左右移动,当移动到某个垃圾的位置上时,可以选择花费 X 点能量将它捡起来(也可以视而不捡)。机器人如果到达垃圾桶,则可以将它携带的垃圾花费 X 点能量倒出。机器人如果携带着 K 件垃圾移动一个单位距离,则需要消耗 (K+1)^2 点能量。问将所有垃圾全部弄到垃圾桶里面去所需消耗的最小能量。
分析:
贪心 + 推性质。
如果机器人一次将多个垃圾一起捡走,那么一定是从走到最后面,再回来。如果机器人第i个垃圾回来,花费为$pos_i imes (1 + 1) ^ 2 + pos_i = 5 pos_i$,如果在i前面再捡一个垃圾,新增加的花费为:$pos_j imes ((1 + 2) ^ 2 - (1 + 1) ^ 2) = 5 pos_j$ 同样再增加一个:$pos_k imes ((1 + 3) ^ 2 - (1 + 2) ^ 2) = 7pos_k$。所以有公式:
$F(i)=left{egin{matrix} 5pos (i=1)\ (2i+1)pos (i>1) end{matrix} ight.$
表示第i个捡的垃圾的花费。
因为系数一样,所以每次捡多少应该都是一样的,枚举每次捡了多少。然后贪心的思路,让最远的点乘以系数最小的,就是让最远的k个点都是第一次拿,次远的k个点都是第二次拿...
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 #define fi(s) freopen(s,"r",stdin); 12 #define fo(s) freopen(s,"w",stdout); 13 using namespace std; 14 typedef long long LL; 15 16 inline LL read() { 17 LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 18 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 19 } 20 21 LL a[200005]; 22 23 int main() { 24 int n = read();LL x = read(); 25 for (int i=1; i<=n; ++i) a[i] = read() + a[i - 1]; 26 LL ans = 1e18; 27 for (int k=1; k<=n; ++k) { 28 LL sum = 0, now = 3; 29 for (int i=n; i>=1; i-=k) { 30 sum += (a[i] - a[max(0, i - k)]) * max(now, 5ll), now += 2; 31 if (sum >= ans) break; 32 } 33 ans = min(ans, sum + 1ll * (k + n) * x); 34 } 35 cout << ans; 36 return 0; 37 }