Description
有 \(n\) 个客人,分别在 \(t_i\) 时刻到访,在每一个客人到访时,暖炉必须是打开的。暖炉初始是关闭的,并且最多只能打开 \(k\) 次。求开着暖炉的最小时间。保证不会有两个客人在同一时间到访。
Solution
假设 \(t_i\) 已经升序排序,那么显然有 \(n-1\) 个间隔是可以选择的,第 \(i\) 个间隔的长度是 \(t_{i+1}-t_i-1\)。
其中,我们最多可以拿掉 \(k-1\) 个区间,显然我们会拿最大的 \(k-1\) 个,于是对其排序即可。
当然,设 \(f[i][j]\) 表示 \([t_i,t_i+1)\) 后,已经用了 \(j\) 次开启,需要的最短时间,这时 \(O(n^2)\) 的 dp 也是显然的。
口胡一个费用流的做法,建立 \(S,S',T\),每个客人当一对点 \(i,i'\),按时间排序后依次连线 \(i' \to i+1\),费用为时差。
\(S \to S'\) 限制总流量 \(k\),\(S' \to i\),\(i' \to T\),费用为 \(0\)。
\(i \to i'\),费用为 \(-M\),其中 \(M\) 是一个很大的负数,通过这样的方式来保证这样的每条边都会被流过。
没验证过,仅供参考。
贪心 CODE
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int n,k,t[N],a[N];
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>t[i];
sort(t+1,t+n+1);
for(int i=1;i<n;i++) a[i]=t[i+1]-t[i]-1;
sort(a+1,a+n);
reverse(a+1,a+n);
int ans=t[n]-t[1]+1;
for(int i=1;i<k;i++) ans-=a[i];
cout<<ans<<endl;
}