给出n个人,每个人有血量T和攻击力D。
你自己可以看做有无限血量和A的攻击力。
战斗为回合制进行,每一回合你先选择一个敌人攻击,将其血量减少你的攻击力的数值。
若一个人的血量<=0则死亡。
然后所有存活的敌人对你进行攻击,每个人对你造成D的伤害。
在战斗开始前你可以先秒杀两个敌人。
求你所受伤害的最小值。
n<=3*10^5,T,D,A<=10^4
显然血量可以直接看做T/A+(T%A>0)
首先考虑没有秒杀的情况。
显然我们每次都会选定一个人一直攻击。
那么我们就是要求出最优的攻击顺序。
假设我们已经找出了一种攻击顺序,那么交换相邻两项会使答案更优的话满足
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef double db;
typedef long long ll;
const int N=3*1e5+5;
struct note{int d,t;}a[N];
struct node{int v;ll c;}t[N],T[N],d[N],D[N];
int n,atk,q[N];
ll c[N],sum,ans;
bool cmp(note x,note y) {
return (db)x.t/x.d<(db)y.t/y.d;
}
db calc(int x,int y) {
if (t[x].v==t[y].v) {
if (t[y].c<=t[x].c) return 0;
else return 1e18;
}
return (db)(t[y].c-t[x].c)/(t[y].v-t[x].v);
}
void solve(int l,int r) {
if (l==r) return;
int mid=(l+r)/2;
solve(l,mid);solve(mid+1,r);
int le=1,ri=0;
fo(i,l,mid) {
while (le<ri&&calc(q[ri-1],q[ri])<calc(q[ri],i)) ri--;
q[++ri]=i;
}
fo(i,mid+1,r) {
while (le<ri&&calc(q[le],q[le+1])>=d[i].v) le++;
ans=min(ans,sum-d[i].c-t[q[le]].c+t[q[le]].v*d[i].v);
}
int i=l,j=mid+1,tot=l;
while (i<=mid&&j<=r)
if (d[i].v>d[j].v) D[tot++]=d[i++];
else D[tot++]=d[j++];
while (i<=mid) D[tot++]=d[i++];
while (j<=r) D[tot++]=d[j++];
i=l,j=mid+1,tot=l;
while (i<=mid&&j<=r)
if (t[i].v<t[j].v) T[tot++]=t[i++];
else T[tot++]=t[j++];
while (i<=mid) T[tot++]=t[i++];
while (j<=r) T[tot++]=t[j++];
fo(i,l,r) d[i]=D[i],t[i]=T[i];
}
int main() {
scanf("%d%d",&n,&atk);
fo(i,1,n) scanf("%d%d",&a[i].d,&a[i].t),a[i].t=a[i].t/atk+(a[i].t%atk>0);
sort(a+1,a+n+1,cmp);
ll res=0;
fo(i,1,n) {
res+=(ll)a[i].t;
c[i]+=(ll)(res-1)*a[i].d;
}
fo(i,1,n) sum+=c[i];
ans=sum;res=0;
fd(i,n,1) {
c[i]+=(ll)res*a[i].t;
res+=(ll)a[i].d;
}
fo(i,1,n) d[i].v=a[i].d,t[i].v=a[i].t,d[i].c=t[i].c=c[i];
solve(1,n);
printf("%lld\n",ans);
}