HDU 5303 Delicious Apples(贪心)
题意:
$给定L\le 10^9的环形路,家在0号点,N\le 10^5颗苹果树,每棵有A_i个苹果,\sum A_i \le 10^5$
$现有一个K\le 10^5的篮子,求从家出发把所有的苹果装回家的最短路程$
分析:
$首先可以发现,肯定是先把近的苹果先拿走,如果拿了远的再拿近的再拿远的路程会交叉,就不优了$
$其次再考虑会不会可能走一圈,发现是可以的,见下图:$
$设起点到a的距离为l_1,到b的距离为l_2,且l_1, l_2 > {L\over 4}, A_a+A_b\le k$
$那么走一圈的路程是L,直接从最近的拿是2(l_1+l_2) > L,此时显然走一圈更优$
$更可以得出l_1,l_2\le {L\over 4}直接拿比较好$
$问题来了,可不可能走多圈呢,还是上面的图,看2圈的情况:$
$不过设A_a = x < k, A_b = k + y, 且A_a+A_b \le 2k$
$显然如果两边都是k的话,就不能绕圈了,所以可能走2圈一定是这样的$
$直接拿的话是2(l_1+2l_2)>{3L\over 2},走2圈是2L,走1圈+先拿k是L+2l_2$
$显然走2圈最差,其次L+2l_2 - (2(l_1+2l_2))=L - (2(l_1+l_2)) < 0,走1圈+先拿k最优$
$显然更多圈的情况其实都可以规约到2圈的情况$
$由于苹果个数10^5,把苹果分开看,l[i]:=左边拿i个苹果的代价,r[i]同理$
$所以问题解决了,只要枚举最后一次2边拿的让它走1圈就好了$
$时间复杂度因为有排序所以是O(nlogn)$
代码:
//
// Created by TaoSama on 2016-03-18
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int L, n, k;
typedef long long LL;
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
int t; scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &L, &n, &k);
vector<LL> l(1, 0), r(1, 0); //l[0] = r[0] = 0
for(int i = 1; i <= n; ++i) {
int x, y; scanf("%d%d", &x, &y);
while(y--) {
if(x << 1 < L) l.push_back(x);
else r.push_back(L - x);
}
}
sort(l.begin(), l.end());
sort(r.begin(), r.end());
for(int i = k; i < l.size(); ++i) l[i] += l[i - k];
for(int i = k; i < r.size(); ++i) r[i] += r[i - k];
LL ans = l.back() + r.back() << 1;
for(int i = 0; i <= k; ++i) {
int a = max(0, (int)l.size() - 1 - i);
int b = max(0, (int)r.size() - 1 - (k - i));
ans = min(ans, L + (l[a] + r[b] << 1));
}
printf("%I64d\n", ans);
}
return 0;
}