题意:对于给定的
N
个飞机降落时刻。现在需要延迟
思路:对于每架飞机的延误费用
Ci
,和新时刻表起飞的时间
Ti
,总花费有这样的公式:
SUM=∑i=1nCi∗(Ti−i)
转化后可得:
SUM=∑i=1nCi∗Ti−∑i=1nCi∗i
可知,后部分等式,为定值,要使得结果最小,需要使得前半部分值最小。
设对于
i,j
两架飞机消耗的总花费
Ci∗(Ti−i)+Cj∗(Tj−j)
如果交换
i,j
的新起降时间可得:
Ci∗(Tj−i)+Cj∗(Ti−j)
设交换后总花费大于原费用可得:
Ci∗(Ti−i)+Cj∗(Tj−j)<Ci∗(Tj−i)+Cj∗(Ti−j)
化简可得:
Ci<Cj
可得贪心策略:
在满足要求的情况下(
Ti>i
),取当前合法解中
Ci
最大的。
#include <bits/stdc++.h>
using namespace std;
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
struct node
{
ll p, c;
node(ll a = 0, ll b = 0)
{
p = a;
c = b;
}
};
struct cmp
{
bool operator()(node x, node y)
{
if (x.c != y.c)return x.c > y.c;
return x.p < y.p;
}
};
set<node, cmp>s;
int a[300000 + 50];
int main()
{
ll k;
int n;
scanf("%d%I64d", &n, &k);
ll ans = 0;
for (int i = 1; i <= n; i++)
{
ll c;
scanf("%I64d", &c);
s.insert(node(i, c));
if (i >= k + 1)
{
a[s.begin()->p] = i;
ans += s.begin()->c*(i - s.begin()->p);
s.erase(s.begin());
}
}
for (int i = 1; i <= k; i++)
{
a[s.begin()->p] = i + n;
ans += s.begin()->c*(i + n - s.begin()->p);
s.erase(s.begin());
}
printf("%I64d\n", ans);
//printf("%I64d\n", ans);
for (int i = 1; i <= n; i++)
{
if (i != 1)printf(" ");
printf("%d", a[i]);
}
printf("\n");
//sp;
}