agc 027 B

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 }
原文地址:https://www.cnblogs.com/mjtcn/p/9720076.html