公式
D - アルバイトのシフト割り当て / Part-Time Job Shift Assignment 解説
by
D - アルバイトのシフト割り当て / Part-Time Job Shift Assignment 解説
by
kyopro_friends
\(A\), \(D\) ともに降順にソートされているとしてよいです。
\(\sum_{j=1}^{M}(A_{f(k)}-D_j)=\sum_{j=1}^{M}A_{f(k)} - \sum_{j=1}^{M}D_j\) であり、第 2 項は定数なので、第 1 項を最大化すればよいです。
\(A_{f(j)}\geq D_j\) の条件を無視すれば、第 1 項は \(A_1+A_2+\ldots+A_M\) が最大値となります。実は、条件を満たす割り当てが存在しない場合を除き、常に \(f(i)=i\) とする割り当て方が可能です。
証明
「$f(i)=i$ という割り当てが条件を満たさないならば、条件を満たす割り当ては存在しない」を示します。この割り当てが条件を満たさないときある $i$ で $A_i < D_i$ となります。そのような最小の $i$ をとると、要求スキル値が $D_i$ 以上の業務が $i$ 個以上存在するにも関わらず、スキル値が $D_i$ 以上のアルバイトが $i$ 人未満しかいないため、条件を満たす割り当ては存在しません。よって求める答えは、全ての \(1 \leq i \leq M\) で \(A_i \geq D_i\) のとき \((A_1+A_2+\dots+A_M)-(D_1+D_2+\dots+D_M)\) 、そうでないとき \(-1\) です。
実装例 (C++)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<int>a(n),d(m);
for(int i=0; i<n; i++) cin >> a[i];
for(int i=0; i<m; i++) cin >> d[i];
sort(a.rbegin(), a.rend());
sort(d.rbegin(), d.rend());
long long ans=0;
for(int i=0; i<m; i++){
if(a[i] < d[i]){
cout << -1 << endl;
return 0;
}
ans += a[i] - d[i];
}
cout << ans << endl;
}
実装例 (Python)
N, M = map(int, input().split())
A = list(map(int, input().split()))
D = list(map(int, input().split()))
A.sort(reverse=True)
D.sort(reverse=True)
ans = 0
for i in range(M):
if A[i] < D[i]:
print(-1)
exit()
ans += A[i] - D[i]
print(ans)
