二分挂了,求调
  • 板块P2782 友好城市
  • 楼主ylch
  • 当前回复0
  • 已保存回复0
  • 发布时间2024/7/11 22:18
  • 上次更新2024/7/11 22:19:14
查看原帖
二分挂了,求调
759881
ylch楼主2024/7/11 22:18

rt

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;

struct Node{
    int nor, sou; // no:north北岸的城市坐标;so:south南岸的城市坐标
}a[maxn];

bool cmp(Node p1, Node p2){
    if(p1.nor != p2.nor) return p1.nor < p2.nor; // 先使得北岸升序
    return p1.sou < p2.sou; // 再让南岸升序(这一条不加也可以)
}

int f[maxn]; // f[i]表示求出来的最长上升子序列中第i个位置的最优解(按照贪心的思路,肯定在某个位置的值尽可能小,留给后面的大小限制就更宽泛,所以位置i的值越小越优)
// 不难看出,f一定单调递增,具有单调性,所以能应用二分优化

void solve()
{
    int n; cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i].nor >> a[i].sou;
    sort(a + 1, a + n + 1, cmp);

    f[1] = a[1].sou; // 第一个直接加入dp数组
    int pos = 1; // pos指向f数组的末尾位置
    for(int i = 2; i <= n; i ++){
        if(f[pos] < a[i].sou){ // 如果它大于最后一个,说明它没有往前插的余地,直接加到最后面
            f[++ pos] = a[i].sou;
        }
        else{ // 否则,在1~pos中找到第一个大于等于它的元素j,并将j替换为a[i].sou。这样可以给后面的元素“留下更为宽泛的限制”,更容易形成最长上升子序列。对答案更优
            // lower_bound(l,r,x) 找到[l,r)区间中第一个大于等于x的元素
            int idx = lower_bound(f + 1, f + pos + 1, a[i].sou) - f; // 地址相减,得到下标
            f[idx] = a[i].sou; // 这里不用考虑idx>pos的情况,因为上面的if已经判断过了    
        }
    }

    cout << pos << '\n'; // pos的值即为f数组的长度,也就是LIS的长度
}

signed main()
{
    ios :: sync_with_stdio(false), cin.tie(0), cout.tie(0);
    solve();
    return 0;
}
2024/7/11 22:18
加载中...