大意: 一扇自动门, 若$t$时刻有人来, 并且门是关的, 自动门会打开$d$时间, [t,t+d]时刻来的人都可以进入, 现在有n个雇员, 分别在$a, 2a, ..., na$时刻来, $m$个客户, 分别在$t_1, t_2,..., t_m$时刻来, 求自动门打开的次数.
数据范围1 ≤ n, a ≤ 109, 1 ≤ m ≤ 105, 1 ≤ d ≤ 1018, 1 ≤ ti ≤ 1018
根据题目的范围, 显然要考虑枚举$m$个客户, 当一个客户$i$来的时候, 先处理$t_i$之前未处理的雇员即可.
为了防止最后还有未处理的雇员, 可以添加一个客户, 让他时间等于n*a, 显然不影响答案.
#include <iostream> #include <algorithm> #include <cstdio> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) using namespace std; typedef long long ll; const int N = 1e6+10; ll n, m, a, d, t[N]; int main() { scanf("%lld%lld%lld%lld", &n, &m, &a, &d); REP(i,1,m) scanf("%lld", t+i); ll now = 0, ans = 0, cur = 1; t[++m] = n*a; PER(i,2,m) if (t[i]<t[i-1]) swap(t[i],t[i-1]); REP(i,1,m) { if (cur<=n&&cur*a<t[i]) { now = cur*a; ll r = d/a+1, tot = (t[i]-now)/a+1; ll q = tot/r; if (q) { ans += q; now += (q-1)*r*a+d; tot -= q*r; cur = now/a+1; } if (tot) { ++ans; now = cur*a+d; cur = now/a+1; } } if (now>=t[i]) continue; now = t[i]+d; cur = now/a+1; ++ans; } printf("%lld ", ans); }