zoukankan      html  css  js  c++  java
  • [SDOI2013]保护出题人

    题目

    题解

    数据确实水,n2 算法能过1e4就算了,1e5都能过一组,服了
    研究题目与样例数据,我们得知一个重要信息,僵尸死了之后,多余的伤害会传到后面去。打死最前面的僵尸才能打后面,僵尸每秒都移动,那么对于第i个僵尸,我们可以将前面的僵尸与i本身绑在一起(生命值之和),求此时需要多少攻击力,即生命值之和除以i离红线的距离
    那么我们轻松可以得到f[i] = max(sum[i] - sum[j - 1]) / (d * (i - j) + x[i])。
    f[i]表示第i关需要最小攻击力
    最后加起来便是答案
    先给一个朴素的代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<ctime>
    using namespace std;
    int n;
    long long sum[100005],a[100005],x[100005],d;
    double ans;
    long long read(){
    	long long x = 0,f = 1;
    	char s = getchar();
    	while (s < '0' || s > '9'){
    		if (s == '-')
    			f = -1;
    		s = getchar();
    	}
    	while (s >= '0' && s <= '9'){
    		x = x * 10 + s - '0';
    		s = getchar();
    	}
    	return f * x;
    }
    int main(){
    	scanf ("%d%lld",&n,&d);
    	for (int i = 1;i <= n;i ++)
    		a[i] = read(),x[i] = read();
    	for (int i = 1;i <= n;i ++){
    		for (int j = i;j >= 2;j --)
    			sum[j] = sum[j - 1] + a[i];
    		sum[1] = a[i];
    		double maxn = 0;
    		for (int j = 1;j <= i;j ++)
    			maxn = max(maxn,1.0 * sum[j] / (d * (j - 1) + x[i]));
    		ans += maxn;
    	}
    	printf("%.0lf
    ",ans);
    }
    

    但这个过不了,我们再观察式子,发现是这(x[i]+d*i,sum[i]),(d * j,sum[j - 1])两点的斜率。所以维护一个下凸包,二分求最大斜率即可
    我太垃圾了,放一个巨佬博客

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<ctime>
    using namespace std;
    struct node{
    	long long  x,y;
    	node(){};
    	node(long long X,long long Y){
    		x = X,y = Y;
    	}
    }Q[100005];
    int n,cnt;
    long long sum[100005],a[100005],x[100005],d;
    double ans;
    double get(node a,node b){
    	return 1.0*(a.y - b.y) / (a.x - b.x);
    }
    int main(){
    	scanf ("%d%lld",&n,&d);
    	for (int i = 1;i <= n;i ++)
    		scanf ("%lld%lld",&a[i],&x[i]);
    	for (int i = 1;i <= n;i ++)
    		sum[i] = sum[i - 1] + a[i];
    	Q[0] = node(0,0);
    	for (int i = 1;i <= n;i ++){
    		node tmp = node(i * d,sum[i - 1]);
    		while (cnt && get(Q[cnt - 1],Q[cnt]) > get(Q[cnt],tmp))
    			cnt --;
    		Q[++ cnt] = tmp;
    		tmp = node(i * d + x[i],sum[i]);
    		int l = 1,r = cnt,pos = 0;
    		while (l <= r){
    			int mid = (l + r) / 2;
    			if (get(Q[mid],tmp) > get(Q[mid - 1],tmp)){
    				pos = mid;
    				l = mid + 1;
    			}
    			else 
    				r = mid - 1;
    		}
    		ans += get(Q[pos],tmp);
    	}
    	printf("%.0lf
    ",ans);
    }
    
  • 相关阅读:
    equals()与=的区别
    HashTable和HashMap的区别
    shell高级用法——磁盘管理 创建虚拟的磁盘映射到一个文件
    shell妙用之——dd命令合并多个烧录文件为一个flash镜像
    自动解包ROM 文件获取uboot,uboot-spl ,uImage, rootfs.tar.gz 并烧写SD卡
    运用层通过shell脚本直接操控gpio
    shell脚本之位运算+for循环+返回值承接+shell小数运算
    shell函数递归调用实现目录的对比拷贝
    用debootstrip制作debian环境的rootfs
    shell命令的高级使用之---选择性copy
  • 原文地址:https://www.cnblogs.com/lover-fucker/p/13566646.html
Copyright © 2011-2022 走看看