hdu5714 思维+区间内线段最

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5714


题目大意:给你n只小船,给你每个船的左端点和右端点,以及航行方向(左,右)和到岸边的距离,每个船的航行距离一样。如果有个人在岸边且只能垂直于岸边拍摄(与岸边呈45度角),问最多可以拍到多少只完整的小船。

思路:

1、首先,因为所有船只航速一样,所以同一方向的船只相对静止。

2、如果在l点可以拍摄到向右航行的船只数目为num1,在r点可以拍摄到向左航行的船只数量为num2,l<=r,那么一定存在某一时刻拍摄到的船只数量等于num1+num2.这个很好证明,两个同样的三角形相向而行,必定会重合。


3、如果有y-x>2z,则该船不可能出现在镜头中。如果y-x<=2z,那么该船可被拍摄的范围是(y-z,x+z),画个图就理解了。但是做的时候把范围搞成了(x+z , y-z)。。。显然错了


4、我们可以处理出所有船只可被拍摄的范围,然后求区间内线段个数最多的点。方法是左端点标记为1,右端点标记为-1,排序后从左到右扫描一遍,遇到1++,遇到-1--;

5、不同方向的船只分开处理。

复杂度nlogn。


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 1000005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define ULL unsigned long long
const long long INF=0x3fffffff;

int n , t;
struct node
{
    int val , flag ,d;

} a[maxn] , b[maxn];

int ans[maxn];

bool cmp(node n1,node n2)
{
    if(n1.val != n2.val) return n1.val < n2.val;
    else if(n1.flag != n2.flag) return n1.flag > n2.flag;
    else return n1.d < n2.d;
}

int main()
{
    scanf("%d" , &t);
    int cas = 0;
    while(t--)
    {
        mem(ans , 0);
        scanf("%d" , &n);
        int x , y ,  z , d;
        int id1 = 0 , id2 = 0;
        for(int i = 0 ; i < n ; i ++)
        {
            scanf("%d %d %d %d" , &x , &y , &z , &d);
            x += 1000000;
            y += 1000000;
            if((y - x) > 2*z) continue;
            a[id1].val = x + z;
            a[id1].d = d;
            a[id1++].flag = -1;
            a[id1].val = y - z;
            a[id1].d = d;
            a[id1++].flag = 1;
        }
        sort(a , a + id1 , cmp);
        int ans1 = 0 ;
        int num = 0;
        for(int i = id1 - 1; i >= 0 ; i --)
        {
            if (a[i].d < 0 && a[i].flag == -1) num++;
            ans[i] = max(ans[i + 1], num);
            if (a[i].d < 0 && a[i].flag == 1) num--;
        }
        num = 0;
        for(int i = 0 ; i < id1 ; i ++)
        {
            if(a[i].d > 0)
            {
                if(a[i].flag == 1) num++;
                ans1 = max(ans1 , num + ans[i]);
                if(a[i].flag == -1) num--;
            }
        }
        printf("Case #%d:\n%d\n", ++cas, ans1);

    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值