【NOIP2016提高A组集训第5场11.2】寻找

在二维平面上,从(0,0)出发,通过只能向右、向下或向右下角移动的方式寻找果实。问题求解的是最多能收集到多少个果实。给定坐标点列表,算法需找出能到达的最多果实数。样例输入和输出展示了具体场景,数据约束保证了n的范围和坐标值的范围。解题关键在于二维偏序或最长不下降子序列的概念应用。" 117638089,8630595,解决C语言VC2010学习版编译时乱码问题,"['编译器', 'C++', '编程问题', '调试技巧', '编码转换']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

“我有个愿望,我希望穿越一切找到你。”
这是个二维平面世界,平面上有n个特殊的果实,我从(0,0)点出发,希望得到尽量多的果实,但是出于某种特殊的原因,我的运动方式只有三种(假设当前我在(x,y)):
1、我可以走到(x+1,y)
2、我可以走到(x,y+1)
3、我可以走到(x+1,y+1)
现在我需要你的帮助,帮我找出我最多能够得到多少个果实。

Input

第一行一个整数n表示有多少个被标记的点
接下来n行每行两个整数x,y表示一个点的坐标

Output

一行一个整数表示答案,表示我最多能够得到多少个果实。

Sample Input

8
-2 -1
-2 -3
0 1
1 1
2 2
3 2
3 2
3 3

Sample Output

6

Data Constraint

对于70%的数据1<=n<=1000
对于100%的数据1<=n<=100000,-10^9<=x,y<=10^9

题解

二维偏序or最长不下降子序列

贴代码

var
    tree:array[0..500005]of longint;
    a:array[0..100005,1..2]of longint;
    c:array[0..100005]of longint;
    i,j,k,l,n,x,y,tot,ans,last:longint;
function max(x,y:longint):longint;
begin
    if x>y then exit(x) else exit(y);
end;
procedure qsort(l,r,x:longint);
var
    i,j,mid,mid1,y:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2,x];
    if x=1 then y:=2 else y:=1;
    mid1:=a[(i+j) div 2,y];
    repeat
        while (a[i,x]<mid) or ((a[i,x]=mid) and (a[i,y]<mid1)) do inc(i);
        while (a[j,x]>mid) or ((a[j,x]=mid) and (a[j,y]>mid1)) do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then qsort(i,r,x);
    if l<j then qsort(l,j,x);
end;
procedure find(v,l,r,x,y:longint);
var
    mid:longint;
begin
    if (l=x) and (r=y) then tot:=max(tot,tree[v]) else
    begin
        mid:=(l+r) div 2;
        if y<=mid then find(v*2,l,mid,x,y) else
        if x>mid then find(v*2+1,mid+1,r,x,y) else
        begin
            find(v*2,l,mid,x,mid);
            find(v*2+1,mid+1,r,mid+1,y);
        end;
    end;
end;
procedure change(v,l,r,x:longint);
var
    mid:longint;
begin
    tree[v]:=max(tree[v],tot);
    if l=r then exit;
    mid:=(l+r) div 2;
    if x<=mid then change(v*2,l,mid,x) else change(v*2+1,mid+1,r,x);
end;
begin
    assign(input,'find.in'); reset(input);
    assign(output,'find.out'); rewrite(output);
    readln(n);
    for i:=1 to n do
    begin
        readln(x,y);
        if (x>=0) and (y>=0) then
        begin
            inc(l);
            a[l,1]:=x; a[l,2]:=y;
        end;
    end;
    n:=l;
    qsort(1,n,2);
    a[0,2]:=-1;
    for i:=1 to n do
    if a[i,2]=a[i-1,2] then c[i]:=c[i-1] else c[i]:=c[i-1]+1;
    for i:=1 to n do a[i,2]:=c[i];
    last:=c[n];
    qsort(1,n,1);
    for i:=n downto 1 do
    begin
        tot:=0;
        find(1,1,last,a[i,2],last);
        inc(tot);
        if tot>ans then ans:=tot;
        change(1,1,last,a[i,2]);
    end;
    writeln(ans);
    close(input); close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值