• [BZOJ3203][SDOI2013]保护出题人


    bzoj
    luogu
    题面不太好简化就不放了qaq。

    sol

    先对僵尸的血量做一个前缀和,然后在第(i)关中视第(j)只僵尸((jle i))的血量为(a_i-a_{j-1}),这样就可以当作是开了穿墙挂,可以一直攻击每一只僵尸直至其死亡。
    考虑最优策略,一定是某一只僵尸在刚好走到门前的时候把他打死。也就是算出打死每一只僵尸所需的伤害,放在一起求个(max)
    形式化的,有(y_i=max_{1le jle i}{frac{a_i-a_{j-1}}{x_i+d imes(i-j)}})。感觉这个东西长得很像是个斜率。
    所以(y_i)就是点((x_i+di,a_i))到所有((dj,a_{j-1}))的斜率最大值。而斜率最大值一定会出现在下凸壳上(别问我怎么知道的),所以对所有的((di,a_{i-1}))维护个下凸壳,然后每次查询的时候二分即可。
    复杂度(O(nlog n))

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    ll gi(){
    	ll x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 1e5+5;
    int n,top;ll d,a[N],x[N];double ans;
    struct node{ll x,y;}q[N];
    double slope(node p,node q){
    	return 1.0*(p.y-q.y)/(p.x-q.x);
    }
    int main(){
    	n=gi();d=gi();
    	for (int i=1;i<=n;++i) a[i]=a[i-1]+gi(),x[i]=gi();
    	for (int i=1;i<=n;++i){
    		node tmp=(node){d*i,a[i-1]};
    		while (top&&slope(q[top-1],q[top])>slope(q[top],tmp)) --top;
    		q[++top]=tmp;tmp=(node){x[i]+d*i,a[i]};
    		int l=1,r=top,res=0;
    		while (l<=r){
    			int mid=l+r>>1;
    			if (slope(q[mid-1],tmp)<slope(q[mid],tmp)) res=mid,l=mid+1;
    			else r=mid-1;
    		}
    		ans+=slope(q[res],tmp);
    	}
    	printf("%.0lf
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    redis配置文件redis.conf总结
    react井字棋小游戏实现及优化
    springboot 如何在请求进入controller之前改变body中的值
    记录一个Springboot启动的问题->sprinboot正常启动但是tomcat却没有启动
    websocket-基于springboot的简单实现
    JVM-垃圾回收
    gRPC-Java实践
    Protocol Buffers—-java
    串口通信学习-基础
    Modbus通信协议学习
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9267467.html
Copyright © 2020-2023  润新知