2023年第十四届蓝桥杯大赛软件类省赛Java大学A组H题太阳

2023年第十四届蓝桥杯大赛软件类省赛Java大学A组H题太阳

题目链接

题目描述

这天,小蓝在二维坐标系的点 (X, Y) 上放了一个太阳,看做点光源。

他拿来了 n 条线段,将它们平行于 x 轴放置在了坐标系中,第 i 条线段的左端点在 xi, yi,长度为 li。线段之间不会有重合或部分重合的情况(但可能出现端点相交)。小蓝想知道有多少条线段能被太阳照亮(一条线段有长度大于 0 的部分被照亮就算)。

输入格式

输入的第一行包含三个正整数 n, X, Y,相邻整数之间使用一个空格分隔。

接下来 n 行,第 i 行包含三个整数 xi, yi, li,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个正整数表示答案。

样例输入

3 10 2000000
5 3 5
6 2 4
0 1 10

样例输出

2

提示

第一条线段在最上面被照亮,第二条线段被第一条完全挡住,第三条线段左边的一段能被照亮。

对于 30% 的评测用例,n ≤ 1000 ;

对于所有评测用例,1 ≤ n ≤ 100000, 0 ≤ xi , X ≤ 107 , 0 < yi ≤ 105 , 0 < li ≤ 100, 106 < Y ≤ 107 。

投影公式推导

太阳 ( X , Y ) (X, Y) (X,Y) 到线段端点 ( x i , y i ) (x_i, y_i) (xi,yi) 的光线斜率为:

k = Y − y i X − x i k = \frac{Y - y_i}{X - x_i} k=XxiYyi

光线直线方程为:

y − y i = k ( x − x i ) y - y_i = k(x - x_i) yyi=k(xxi)

求与x轴交点( y = 0 y=0 y=0):

x proj = X ⋅ y i − x i ⋅ Y y i − Y = x i ( Y − y i ) + X y i Y − y i x_{\text{proj}} = \frac{X \cdot y_i - x_i \cdot Y}{y_i - Y} = \frac{x_i(Y - y_i) + X y_i}{Y - y_i} xproj=yiYXyixiY=Yyixi(Yyi)+Xyi
AC代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

class java {
    static int X,Y;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pt  = new PrintWriter(System.out);
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        X = Integer.parseInt(st.nextToken());
        Y = Integer.parseInt(st.nextToken());
        List<int[]> list = new ArrayList<>();
        for(int i = 0;i<n;i++){
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            int l = Integer.parseInt(st.nextToken());
            list.add(new int[]{x,x+l,y});
        }
        //降序排列
        Collections.sort(list,(o1,o2)->Integer.compare(o2[2],o1[2]));
        TreeMap<Double,Double> map = new TreeMap<>();
        int res = 0;
        for(int[] arr:list){
            //投影区间
            double l = y0x(arr[0],arr[2]);
            double r = y0x(arr[1],arr[2]);
            if(merge(map,l,r)){
                res++;
            }
        }
        pt.println(res);
        pt.flush();
        pt.close();
     }
    public static double y0x(int x, int y) {
        if (x == X) return x;
        long a = (long) X * y;
        long b = (long) Y * x;
        return (b - a) / ((Y - y) * 1.0);
    }
    //区间合并
    public static boolean merge(TreeMap<Double,Double> map,double left,double right){
        Double l = map.floorKey(left);
        if(l!=null&&map.get(l)>=left){
            if(l<=left&&map.get(l)>=right){
                return false;
            }
            left = Math.min(l,left);
            right = Math.max(map.get(l),right);
            map.remove(l);
        }
        Double r = map.ceilingKey(left);
        while(r!=null&&r<=right){
            right = Math.max(right,map.get(r));
            map.remove(r);
            r = map.ceilingKey(left);
        }
        map.put(left,right);
        return true;
    }
}

时间复杂度: ​O(n log n)

2023年第十四届蓝桥杯大赛软件类省赛Java大学A组H题太阳_第1张图片

你可能感兴趣的:(蓝桥杯,java)