• [SNOI2017]炸弹


    题目:BZOJ5017。

    题目大意:
    有一些炸弹排成一行,每个炸弹都有一个位置(X_i)和爆炸半径(R_i)。一个炸弹爆炸时,处在其爆炸范围内的其他炸弹会跟着爆炸。
    即炸弹(i)爆炸时,对任意一个炸弹(j)((j eq i)),若(X_i-R_ileqslant X_jleqslant X_i+R_i),则炸弹(j)爆炸。

    设引爆炸弹(i)将会使(b_i)个炸弹爆炸(包括其本身),求(sumlimits _{i=1}^n i imes b_i)。

    解题思路:
    设(l_i,r_i)分别表示引爆炸弹(i)时最左边爆炸的炸弹和最右边爆炸的炸弹,初始为(i)。
    首先更新(l)。
    若(X_i-X_{l_i -1}leqslant R_i),则炸弹(l_i-1)能被连锁反应到,则用(l_{l_i -1})更新(l_i)。然后若(R_{l_i}-(X_i -X_{l_i})>R_i),则更新(R_i)(已经计算对左边的贡献,所以(R_i)保存向右炸的长度即可)。
    同理更新(r_i)即可,由于(R_i)已经最大,所以(r_i)更新出来肯定最优。同时令(l_i=max { l_i,l_{r_i} } )(可能右边那个炸弹炸得更左边)。
    然后计算答案即可。时间复杂度(O(n))。

    C++ Code:

    #include<bits/stdc++.h>
    #define N 500005
    #define LoveLive long long
    int l[N],r[N],n;
    LoveLive x[N],R[N];
    template<typename T>
    inline T max(const T x,const T y){return x>y?x:y;}
    template<typename T>
    inline T min(const T x,const T y){return x<y?x:y;}
    inline LoveLive readint(){
    	int c=getchar(),f=0;
    	LoveLive d=0;
    	for(;!isdigit(c);c=getchar())f=c=='-';
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return f?-d:d;
    }
    int main(){
    	n=readint();
    	for(int i=1;i<=n;++i)x[i]=readint(),R[i]=readint(),l[i]=r[i]=i;
    	for(int i=2;i<=n;++i)
    	while(l[i]>1&&x[i]-x[l[i]-1]<=R[i])
    	l[i]=l[l[i]-1],R[i]=max(R[i],R[l[i]]-(x[i]-x[l[i]]));
    	for(int i=n-1;i;--i)
    	while(r[i]<n&&x[r[i]+1]-x[r[i]]<=R[i])
    	r[i]=r[r[i]+1],l[i]=min(l[i],l[r[i]]);
    	LoveLive ans=0;
    	for(int i=1;i<=n;++i)
    	ans=(ans+(r[i]-l[i]+1LL)*i)%1000000007;
    	std::cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    函数
    vue中v-for循环如何将变量带入class的属性名中
    代码规范 前端导航
    2019.8.5 mysql 删除 更新
    2019.8.1
    2019.7.31 Xshell简单学习
    日常使用知识点
    FormData实现文件多次添加累加上传和选择删除
    上传图片
    验证码
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9178495.html
Copyright © 2020-2023  润新知