题目描述
敌方有 (n) 只怪,每只的攻击力为 (a_i),血量为 (d_i)。
我方只有一只攻击力为 (b) 的怪。
每回合战斗的流程为:
- 我方选择敌方某只怪进行攻击,令其血量减少 (b),若此时该只怪的血量(leq) 0则死亡。
- 若敌方第 (i) 只怪仍然存活,则对我方造成 (a_i) 的伤害。
初始时你可以选择敌方的两只怪进行秒杀。
求所受伤害最小值。
解法:
显然我方只有在连续攻击一只怪致死后,才会换下一只。设第 (i) 只怪需要被连续攻击:
[c_i=lfloor frac{d_i-1}{b}
floor +1
]
若没有秒杀的操作,只考虑我方的攻击顺序。
则第 (i) 只怪排在第 (j) 只之后,当且仅当:
[c_i*a_j>c_j*a_i
]
于是我们按照这一关键字排序即可。
现考虑秒杀操作。若仅秒杀一只怪 ,则伤害值会减小:
[e_i=a_isum_{j=1}^ {i-1}c_j+a_i(c_i-1)+c_isum_{j=i+1}^{n}a_j
]
考虑若确定秒杀第 (i) 只怪,再秒杀第 (j) 只怪比秒杀第 (k) 只怪优(其中(j),(k) < (i) 且 (c_j)>(c_k)),当且仅当:
[e_i+e_j-a_i*c_j>e_k+e_i-a_i*c_k
]
化简得:
[a_i> frac {e_j-e_k}{c_j-c_k}
]
这是一个斜率优化模型(不懂的话右转斜率优化),显然可以用李超树动态维护,但我不会,我们以c为横坐标,e为纵坐标的坐标轴上,有可能成为最优决策的只有上凸的点。
维护一个单调递减的上凸壳即可。
但注意到 (a_i) 和 (c_j) 无序。
考虑用 (CDQ) 分治处理。
对于区间 ([l,r]),将 ([l,mid]) 和 ([mid+1,r]) 分别按 (c) 和 (a) 排序,即可进行斜率优化。
复杂度 (O(nlog^2n))。
代码:
//#pragma GCC optimize(2)
//#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int N=1e6+5;
const ll mod=998244353;
const double eps=1e-5;
const double pi=acos(-1);
#define ls p<<1
#define rs p<<1|1
struct node
{
ll x,y,z;
}a[N];
int q[N];
bool cmp(node x,node y)
{
return x.x*y.y>x.y*y.x;
}
bool cmpy(node x,node y)
{
return x.y<y.y;
}
bool cmpx(node x,node y)
{
return x.x<y.x;
}
ll ans,sum;
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid);cdq(mid+1,r);
sort(a+l,a+mid+1,cmpy);sort(a+mid+1,a+r+1,cmpx);
int s=1,e=1;q[1]=0;
for(int i=l;i<=mid;i++)
{
while(s<e&&(a[q[e]].z-a[q[e-1]].z)*(a[i].y-a[q[e]].y)<=(a[i].z-a[q[e]].z)*(a[q[e]].y-a[q[e-1]].y)) e--;
q[++e]=i;
}
for(int i=mid+1;i<=r;i++)
{
while(s<e&&(a[q[s]].z-a[q[s+1]].z)<=a[i].x*(a[q[s]].y-a[q[s+1]].y)) s++;
ans=min(ans,sum-a[i].z-a[q[s]].z+a[i].x*a[q[s]].y);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
ll A=0,B=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y;
A+=a[i].x;a[i].y=(a[i].y-1)/m+1;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
A-=a[i].x;B+=a[i].y;
a[i].z=a[i].x*(B-1)+A*a[i].y;
sum+=a[i].x*(B-1);
}
ans=sum;
cdq(1,n);
cout<<ans<<endl;
return 0;
}