【HDOJ】【BestCoder 2nd Anniversary】1003 Wool

问题描述

黎明时, Venus  Psyche  定下了第二个任务。她要渡过河,收集对岸绵羊身上的金羊毛。

那些绵羊狂野不驯,所以 Psyche  一直往地上丢树枝来把它们吓走。地上现在有 n  根树枝,第i 根树枝的长度是 a i  

如果她丢的下一根树枝可以和某两根树枝形成三角形,绵羊就会被激怒而袭击她。

现在Psyche手中只有长度不小于 L  且不大于R 的树枝。请你帮忙计算,她下一根可以丢多少种不同长度的树枝而不会把绵羊激怒呢?

输入描述

第一行,一个整数 T(1T10)  ,代表数据组数。

对于每组数据,第一行有三个整数 n,L,R  (2n10 5 ,1LR10 18 )  .

第二行, n  个整数,第i 个整数为 a i   (1a i 10 18 )  代表第 i  根树枝的长度。

输出描述

输出T 行,对于每组数据,输出选取方式总数。

输入样例

2 
2  1  3 
1  1 
4  3  10 
1  1  2  4 

输出样例

2 
5 

Hint 

对于第一组数据,可以选用长度为 2,3  的树枝。
对于第二组数据,可以选用长度为 6,7,8,9,10  的树枝。

Solution 
这一题只需要考虑地板上的树枝与扔下去的树枝构成三角形。
对于地板上的两根树枝,长度为 a,b  (a>b)  ,它们会让 (ab,a+b)  这个区间长度内的树枝无法扔下。
那么考虑对于一根长度为 a i   的树枝,对所有的 a j a k a i   ,会有 (a i a j ,a i +a j )(a i a k ,a i +a k ) 
我们考虑记录每根树枝为主,它与比其小的树枝能构成三角形的区域。这样我们就有了 2n  个事件点,每个事件点的含义是从这个点开始,后面一段区间被覆盖了,或者是从某个区间的影响范围到这个点为止。
至于如何求出事件点……对 a  排序,与a i  产生事件点的元素就是 a i1   。然后我们再对事件点排序,扫描过去统计答案。
扫到左端点,区间值加 1  ,右端点减1 ,一段区间的值如果大于 0  <script id="MathJax-Element-19591" type="math/tex">0</script>说明这个区间被覆盖了,不能选,否则加进答案

坑点:
1、各种边界(博主原本有些变量没开longlong,在奇怪的地方炸了)
(2、比赛时标程写错了……)

#include<stdio.h>
#include<algorithm>
#define M 200005

typedef long long ll;

struct seg{ll c,p;}b[M];

ll l,r,ans,a[M],p,now,n,t;

inline bool cmp(const seg &a,const seg &b){return a.c<b.c;}

int main()
{
    scanf("%I64d",&t);
    while (t--)
    {
        scanf("%I64d%I64d%I64d",&n,&l,&r);
        ans=now=p=0;
        for (int i=1;i<=n;i++) scanf("%I64d",a+i);
        std::sort(a+1,a+n+1);
        for (int i=1;i<n;i++)
        {
            b[i].c=a[i+1]-a[i]+1,b[i].p=1;
            b[i+n-1].c=a[i+1]+a[i],b[i+n-1].p=-1;
        }
        int m=(n-1)<<1;
        std::sort(b+1,b+m+1,cmp);
        for (int i=1;b[i].c<l;i++) now+=b[p=i].p;
        b[p++].c=l;
        for (;p<=m && b[p].c<=r;)
        {
            if (now<=0) ans+=b[p].c-b[p-1].c;
            now+=b[p++].p;
            while (b[p].c==b[p-1].c) now+=b[p++].p;
        }
        if (now<=0) ans+=r-b[p-1].c+1;
        printf("%I64d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值