题目描述
敌方有n台人形兵器,每台的攻击力为Ai,护甲值为Di。我方只有一台人形兵器,攻击力为ATK。战斗看作回合制,
每回合进程如下:
·1 我方选择对方某台人形兵器并攻击,令其护甲值减少ATK,
若护甲值<0则被破坏。
·2 敌方每台未被破坏的人形兵器攻击我方基地造成Ai点损失。
但是,在第一回合开始之前,某两台敌方的人形兵器被干掉了(秒杀)。问最好情况下,我方基地会受到多少点损
失。
偏序性
先来思考不秒杀要怎么攻击,因为我们肯定有一个攻击顺序(即一定会打死一个再打另一个)
设b表示一个人被打死的所需次数,对于一种攻击方案,什么时候可以交换相邻两项i和i+1呢?推式子发现
biai>bi+1ai+1
这就是偏序关系了,因此按照偏序关系排序,就是攻击顺序。
CDQ分治
我们用c表示删去一个人会使受到的伤害降低多少,这个比较容易计算,i本身无法攻击,i之后攻击次数减少。
如果只删一个人找最大的ci就行了,不过我们可以删两个人。
假如第二个删的人是i,之前还要删一个x。
删去这两个人会使伤害下降
c[i]+c[x]−a[i]∗b[x]
这个要怎么做啊……
一个人与前面所有人相关……CDQ经典模型!
于是CDQ分治一发,每次用前面的影响后面的。
可以把前面的根据b值降序排序,后面的根据a值升序排序,这样就可以单调队列维护了(大概是个决策单调性,式子随便化化就好了)
直接上排序我们两个log,可以先分治子区间,再归并排序,就是一个log了。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn=300000+10;
int a[maxn],d[maxn],b[maxn],id[maxn],A[maxn],B[maxn],C[maxn];
ll c[maxn];
int dl[maxn];
ll xy[maxn];
int i,j,k,l,t,n,m,v,head,tail;
ll ans,sum,wdc;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
bool cmp(int x,int y){
return (db)b[x]/a[x]<(db)b[y]/a[y];
}
ll getxy(int x,int y){
if (b[x]==b[y]){
if (c[x]<=c[y]) return 0;
else return 1e15;
}
return ceil((db)(c[y]-c[x])/(b[y]-b[x]));
}
void solve(int l,int r){
if (l==r) return;
int i,j,k;
ll t;
int mid=(l+r)/2;
solve(l,mid);
solve(mid+1,r);
head=1;tail=0;
fo(i,l,mid){
while (head<=tail&&getxy(dl[tail],B[i])<=xy[tail]) tail--;
dl[++tail]=B[i];
if (head==tail) xy[tail]=0;else xy[tail]=getxy(dl[tail-1],B[i]);
}
fo(i,mid+1,r){
while (head<tail&&xy[head+1]<=a[A[i]]) head++;
t=c[A[i]]-(ll)a[A[i]]*b[dl[head]]+c[dl[head]];
if (sum-t<ans) ans=sum-t;
}
j=l;k=mid+1;t=l;
while (t<=r){
if (j>mid) C[t++]=A[k++];
else if (k>r) C[t++]=A[j++];
else if (a[A[j]]<=a[A[k]]) C[t++]=A[j++];
else C[t++]=A[k++];
}
fo(i,l,r) A[i]=C[i];
j=l;k=mid+1;t=l;
while (t<=r){
if (j>mid) C[t++]=B[k++];
else if (k>r) C[t++]=B[j++];
else if (b[B[j]]>=b[B[k]]) C[t++]=B[j++];
else C[t++]=B[k++];
}
fo(i,l,r) B[i]=C[i];
}
int main(){
//freopen("sz.in","r",stdin);freopen("sz.out","w",stdout);
n=read();v=read();
t=0;
fo(i,1,n){
j=read(),k=read();
if (j) a[++t]=j,d[t]=k;
}
n=t;
fo(i,1,n) b[i]=ceil((db)d[i]/v),id[i]=i;
sort(id+1,id+n+1,cmp);
wdc=0;
fo(i,1,n){
wdc+=(ll)b[id[i]];
c[id[i]]=(ll)(wdc-1)*a[id[i]];
}
fo(i,1,n) sum+=c[i];
wdc=0;
fd(i,n,1){
c[id[i]]+=(ll)wdc*b[id[i]];
wdc+=(ll)a[id[i]];
}
fo(i,1,n) A[i]=B[i]=id[i];
ans=sum;
solve(1,n);
printf("%lld\n",ans);
}