zoukankan      html  css  js  c++  java
  • 【YbtOJ#643】机器决斗

    题目

    题目链接:https://www.ybtoj.com.cn/contest/113/problem/3

    (nleq 3 imes 10^5,A,D,ATKleq 10^4)

    思路

    首先直接令 (b_i=lceilfrac{d_i}{ATK} ceil)
    不难发现如果选择打一个机器人,那么一定会把它打到死。不然先打下一个打死的会更优。
    那么问题转化为有一个长度为 (n) 的排列 (p),我们需要最小化

    [sum^{n}_{i=1}a_i imes ((sum_{j=1}^{i}b_i)-1) ]

    这个东西跟国王游戏类似,考虑调整法:对于最终序列相邻的两项 (i,j),交换他们的代价是 (a_ib_j-a_jb_i),也就是说,最终相邻两项必然有 (a_ib_j>a_jb_i)。直接排序就可以了。
    接下来考虑删除两个机器人后的最小代价。记 (f_i=a_i(sum^{i}_{j=1}b_j)-1,g_i=b_i(sum_{j=i+1}^{n}a_j)),假设我们删除 (x,y) 两个机器人,代价就是

    [(sum^{n}_{i=1}f_i)-f_x-g_x-f_y-g_y+b_xa_y ]

    我们只需要最小化上面这个东西。
    考虑枚举 (x),那么等价于最大化 (f_y+g_y-b_xa_y)。我们可以把这个东西看成一个关于 (b_x) 的一次函数,那么其实就是李超树的板子。直接维护区间直线“最大值位置最多”的直线即可。
    时间复杂度 (O(nlog n))
    除此之外,还可以用平衡树或者 CDQ 分治维护上凸壳。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=300010;
    int rt,n,m;
    ll ans,sum,f[N],g[N];
    
    struct node
    {
    	int a,b;
    }a[N];
    
    bool cmp(node x,node y)
    {
    	return x.b*y.a<x.a*y.b;
    }
    
    bool check(int x,int i,int j)
    {
    	return f[j]+g[j]-a[j].a*x<f[i]+g[i]-a[i].a*x;
    }
    
    struct SegTree
    {
    	int tot,lc[N*4],rc[N*4],res[N*4];
    	
    	int update(int x,int l,int r,int i)
    	{
    		if (!x) x=++tot;
    		int j=res[x];
    		if (l==r)
    		{
    			if (!j || check(l,i,j)) res[x]=i;
    			return x;
    		}
    		if (!j || (check(l,i,j) && check(r,i,j))) return (res[x]=i),x;
    		if (!check(l,i,j) && !check(r,i,j)) return x;
    		int mid=(l+r)>>1;
    		if (f[i]+g[i]>f[j]+g[j])
    		{
    			if (check(mid,i,j))
    				rc[x]=update(rc[x],mid+1,r,j),res[x]=i;
    			else
    				lc[x]=update(lc[x],l,mid,i);
    		}
    		else
    		{
    			if (check(mid,i,j))
    				lc[x]=update(lc[x],l,mid,j),res[x]=i;
    			else
    				rc[x]=update(rc[x],mid+1,r,i);
    		}
    		return x;
    	}
    	
    	int query(int x,int l,int r,int k)
    	{
    		if (!x) return 0;
    		if (l==r) return res[x];
    		int mid=(l+r)>>1,p;
    		if (k<=mid) p=query(lc[x],l,mid,k);
    			else p=query(rc[x],mid+1,r,k);
    		if (!p || check(k,res[x],p)) return res[x];
    		return p;
    	}
    }seg;
    
    int main()
    {
    	freopen("fittest.in","r",stdin);
    	freopen("fittest.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&a[i].a,&a[i].b);
    		a[i].b=(a[i].b-1)/m+1;
    	}
    	sort(a+1,a+1+n,cmp);
    	for (int i=1;i<=n;i++)
    	{
    		ans+=a[i].b;
    		f[i]=(ans-1)*a[i].a;
    		sum+=f[i];
    	}
    	ans=0;
    	for (int i=n;i>=1;i--)
    	{
    		g[i]=ans*a[i].b;
    		ans+=a[i].a;
    	}
    	ans=sum;
    	for (int i=n-1;i>=1;i--)
    	{
    		rt=seg.update(rt,1,1e4,i+1);
    		int j=seg.query(rt,1,1e4,a[i].b);
    		ans=min(ans,sum-f[i]-g[i]-f[j]-g[j]+a[i].b*a[j].a);
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    win10没有新建文件夹
    js暂停的函数
    Mini ORM——PetaPoco笔记
    阻止网页内部滚动条mousewheel事件冒泡
    setTimeout调用带参数的函数的方法
    spring入门--Spring框架底层原理
    spring入门——applicationContext与BeanFactory的区别
    mybatis的Sql语句打印
    Sql语句中IN和exists的区别及应用
    Jenkins学习
  • 原文地址:https://www.cnblogs.com/stoorz/p/14402069.html
Copyright © 2011-2022 走看看