观察到很小,于是考虑在时间轴上。
设为在时刻出发的人数。
设是在时刻出发,前分钟等待时间最少的值。
所以
单独看后面那一坨东西:
然后弄一个的前缀和和的前缀和。
于是变成
代回去:
然后50pts
拆。
然后设
于是就是一条斜率为的直线。
然后显然单调递增。
好了。斜率优化。
using namespace std;
#define ll int
#define f(i,a,b) for(ll i=a;i<=b;i++)
inline ll rd() {
ll x=0,f=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))x=x*10+c-'0',c=getchar();
return x*f;
}
#define d rd()
#define pb push_back
const ll N=300010;
struct edge{ll v,w,nx;}e[N<<1];
ll hd[N],cnt;
void add(ll u,ll v,ll w){e[++cnt]=(edge){v,w,hd[u]};hd[u]=cnt;}
ll qp(ll a,ll b,ll p){
ll ans=1;while(b){
if(b&1)ans=ans*a%p;
a=a*a%p;b>>=1;
}return ans;
}ll n,m;
ll c[4100010];
ll dp[4100010];
ll a[4100010],b[4100010];
ll mx,ans=1000000000;
double sl(ll i,ll j){
double xone=a[i],xtwo=a[j];
double yone=dp[i]+b[i];
double ytwo=dp[j]+b[j];
return (ytwo-yone)/((xone==xtwo)?1e-9:xtwo-xone);
}ll q[4100010],h,t;
int main(){
n=d,m=d;f(i,1,n){ll x=d;a[x]++,b[x]+=x;mx=max(mx,x);}
n=mx+m-1;f(i,1,n)a[i]+=a[i-1],b[i]+=b[i-1];
h=1,t=0;
f(i,0,n){if(i-m>=0){while(h<t&&sl(q[t-1],q[t])>=sl(q[t],i-m))t--;q[++t]=i-m;}
while(h<t&&sl(q[h],q[h+1])<=(double)i)h++;
ll j=q[h];dp[i]=i*a[i]-b[i];
if(h<=t)dp[i]=min(dp[i],dp[j]+i*(a[i]-a[j])-(b[i]-b[j]));
}f(i,mx,n)ans=min(ans,dp[i]);
printf("%d",ans);
return 0;
}