bzoj5017 [Snoi2017]炸弹 O(n)递推

标签: bzoj 5017 snoi 炸弹 思维题
26人阅读 评论(0) 收藏 举报
分类:

5017: [Snoi2017]炸弹

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 320  Solved: 118
[Submit][Status][Discuss]

Description

在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: 
Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。 
现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢? 

Input

第一行,一个数字 N,表示炸弹个数。 
第 2∼N+1行,每行 2 个数字,表示 Xi,Ri,保证 Xi 严格递增。 
N≤500000
−10^18≤Xi≤10^18
0≤Ri≤2×10^18

Output

一个数字,表示Sigma(i*炸弹i能引爆的炸弹个数),1<=i<=N mod10^9+7。 

Sample Input

4
1 1
5 1
6 5
15 15

Sample Output

32


HINT

Source

[Submit][Status][Discuss]


HOME Back

去年省选题啊,要是我去年省选肯定不会做。

网上的题解都是线段树优化建图+tarjan缩点+topo排序,这样做不仅复杂度高,而且代码量大,我还是讲一下当时的正解吧(雾

我们定义l[i]为炸弹i经过连锁反应之后能炸到的最靠左的炸弹是哪个,r[i]对称同理,R[i]为炸弹i的爆炸半径。

初始化l[i]=r[i]=i;

然后我们先求出l[i],具体求法为:

如果x[i]-x[l[i]-1]<=R[i]的话,左边那个炸弹是可以被影响到的,所以我们用l[l[i]-1]更新l[i],之后我们还需要更新R[i],因为左边的炸弹能够连锁反应,扩大炸弹i的实际爆炸范围,但是我们已经处理了左边,不需要R[i]的扩大对于左边的贡献了,所以我们只需要计算对右边的贡献,炸弹i通过引爆左边的炸弹,左边的炸弹又能影响到炸弹i右边的炸弹,而且还能使得R[i]变大,很明显R[l[i]]是R[i]的至少2倍才可行,因为我们只需要计算对右边的贡献,所以需要减掉i和l[i]之间的距离,具体见代码。

之后有了没个炸弹对右边的影响范围,我们求r[i]简直是易如反掌:

考虑从右向左求,如果x[r[i]+1]-x[i]<=新的R[i]的话,可以产生贡献,同理更新,同时我们要用l[r[i]]更新l[i],因为可能更靠左,这个时候的l都是已经求好的,所以不用在线更新。

之后统计答案即可。

复杂度:这是一个比较玄学的东西,但是大概这样:我们求解一个l[]或者r[]的时候,用来递推他的l[i]-1/r[i]+1已经是以前递推出来的极限值了,更新之后再次比较一定不会满足while循环的条件,所以while循环只会执行一次,这样时间复杂度就是O(n),我在loj上进行了测试,结果就是n-1;

代码极其好写:

#include <bits/stdc++.h>
using namespace std;
long long n,x[500005],R[500005],l[500005],r[500005],A;
main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld%lld",&x[i],&R[i]),l[i]=r[i]=i;
    for(int i=1;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;i>=1;i--) 
        while(r[i]<n&&x[r[i]+1]-x[i]<=R[i])
            r[i]=r[r[i]+1],l[i]=min(l[i],l[r[i]]);
    for(int i=1;i<=n;i++) A=(A+i*(r[i]-l[i]+1))%1000000007;
    printf("%lld",A);
}   

查看评论

bzoj5017: [Snoi2017]炸弹

线段树优化建图+暴力
  • qq_36797743
  • qq_36797743
  • 2017-09-07 13:30:03
  • 481

bzoj5017 [Snoi2017]炸弹(tarjan缩点+拓扑序dp+线段合并+线段树优化建图)

首先我们可以发现每个点能引爆的炸弹是一个连续的区间。相邻的点能引爆的区间肯定不会相离。每个点向他能引爆的点连边,建出一张有向图,Tarjan缩点(一个scc内的点都可以互达,合并他们能到达的区间即可)...
  • Icefox_zhx
  • Icefox_zhx
  • 2017-12-22 22:07:41
  • 151

[bzoj5017/Snoi2017]炸弹

题目大意在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。 对...
  • WorldWide_D
  • WorldWide_D
  • 2017-10-23 20:36:45
  • 230

bzoj 5017 炸弹 线段树优化建图+tarjan+拓扑排序

题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引...
  • shiyongyang
  • shiyongyang
  • 2017-09-14 20:21:08
  • 279

5017: [Snoi2017]炸弹

题目链接题目大意:在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆...
  • Mmh2000
  • Mmh2000
  • 2018-02-10 20:36:24
  • 56

bzoj 5017: [Snoi2017]炸弹 线段树优化建图+tarjan+拓扑排序

题意 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。 现在,...
  • qq_33229466
  • qq_33229466
  • 2018-01-20 07:57:58
  • 110

[暴力DP][暴力STL]SNOI2017 && LOJ#2256. 英雄联盟

列出DP方程 fi,j=min{fi−1,jk+k×Ci,k|j且k≤Ki }f_{i,j}=min\{ f_{i-1,{j\over k}}+k\times C_i,k|j且k\leq K_i~\...
  • Coldef
  • Coldef
  • 2017-07-06 20:42:47
  • 574

[ 线段树 tarjan缩点 ] [ SNOI2017 ] BZOJ5017

一个暴力的思想是每个点向能引爆它的点连边,求出强联通分量统计答案。但这样是 O(n2)O(n^2) 的。然后线段树优化建图就好了。 #include #include #include #inc...
  • gjghfd
  • gjghfd
  • 2018-01-16 15:43:11
  • 76

已知递推式求第N项的O(logN)算法 (递推式转化为矩阵)

若有递推式f(n)=a(1)f(n-1)+a(2)f(n-2)+…+a(m)f(n-m),则可转化为以下矩阵形式: (你可以自己验算一下) 随后快速幂即可。 (求F(n)就相当于求上...
  • synapse7
  • synapse7
  • 2014-01-26 08:09:47
  • 1499

bzoj5017 [Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

这题原文地址 题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹...
  • elijahqi
  • elijahqi
  • 2017-12-22 19:13:49
  • 48
    个人资料
    持之以恒
    等级:
    访问量: 1536
    积分: 379
    排名: 20万+
    文章存档
    友情链接