CF883A.Automatic Door Solution

Link

首先,我们做出如下约定:

将整个时间以客人的时间分隔成n,分别是

\[(a[i-1],a[i]] \]

,其中第一段是(0,a[1]),最后一段是

\[(a[i],max(a[i],n*a)) \]

由于每一组中的有雇员,雇员的开门可能使得客人不需要开门,因此引入一个last量表示前一组的最后一个开门向后一组延续了多少秒

可以处理出如果是雇员开门,那么包含其在内的之后的

\[tt=d/a+1 \]

个雇员将不需要开门,因此,在每一段内,我们先求出这一段内有多少个雇员,再把这些雇员以tt为一组分成group

image-20220215162735262

如果这一段内没有雇员,即0组,则直接让res++,last=d

如果有一组或多组(k组),处理思路是记录一个l量,先让l指向k组的开端,若l+d>=r,则说明这一段的右客人不需要开门,且右l+d-r的盈余时间,则last=l+d-r,否则右客人需要开门,res++,last=d

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define int long long
using namespace std;
int n, m, a, d;
vector<int> t;
signed main()
{

	cin >> n >> m >> a >> d;
	for (int i = 1; i <= m; i++) {
		int c;
		cin >> c;
		t.push_back(c);
	}
    //排序后去重
	sort(t.begin(), t.end());
	t.erase(unique(t.begin(), t.end()), t.end());
	int m = t.size();
	int last = 0, l , r , res = 0;
	int tt = d / a + 1;//one can hold
	for (int i = 0; i < m; i++) {
		r = t[i];
		l = (i == 0) ? 0 : t[i - 1];
		if (l == r) {
			res++;
			last = d;
			continue;
		}
		if (last >= r - l) {
			last -= r - l;
			continue;
		}
		int hold = min(n, r / a) - min(n, (l + last) / a);
		int group = (hold + tt - 1) / tt;
		l = ((l + last) / a + 1)*a;
		res += (hold + tt - 1) / tt;
		if (!group) {
			res++, last = d;
			continue;
		}
		if (group == 1) {
			if (l + d >= r)last = l + d - r;
			else res++, last = d;
			continue;
		}
		l += ((hold%tt==0)?(hold / tt-1):(hold/tt))*tt*a;
		l += d;
		if (l >= r)last = l - r;
		else res++, last = d;
	}
	if (t[m - 1] + last <= n * a) {
		res += ((n - (t[m - 1] + last) / a) + tt - 1) / tt;
	}
	cout << res;
}