P2782 友好城市 LIS/nlogn

解题思路

这道题目要求我们通过修改最少的数字,使得给定的序列变成严格递增序列。关键点在于:

  1. 问题转化:最少修改的数字数量 = 序列总长度 - 最长严格递增子序列(LIS)的长度

  2. LIS算法:使用O(nlogn)的贪心+二分法来高效计算最长严格递增子序列

  3. 严格递增处理:对于每个元素a[i],在LIS数组中寻找第一个≥a[i]的位置进行替换

代码注释

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, inf = 0x3f3f3f3f;

int a[N];    // 存储原始序列
int n;       // 序列长度
int f[N];    // f数组用于维护LIS序列
int top;     // 当前LIS的长度

// 二分查找函数:找到f数组中第一个≥x的位置
int find(int x) {
    int l = 1, r = top, res = -1;
    while(l <= r) {
        int mid = (l + r) >> 1;  // 取中间位置
        if(x <= f[mid]) {        // 如果x小于等于中间值
            res = mid;           // 记录可能的位置
            r = mid - 1;         // 继续在左半部分查找
        }
        else {
            l = mid + 1;         // 否则在右半部分查找
        }
    }
    return res;                  // 返回找到的位置(没找到返回-1)
}

int main() {
    cin >> n;
    // 输入序列
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    // 初始化f数组为极大值
    memset(f, inf, sizeof(f));
    
    // 计算LIS
    for(int i = 1; i <= n; i++) {
        // 在f数组中查找第一个≥a[i]的位置
        int pos = find(a[i]);
        if(pos == -1) {
            // 如果a[i]比所有元素都大,扩展LIS
            f[++top] = a[i];
        }
        else {
            // 否则替换第一个≥a[i]的元素
            f[pos] = a[i];
        }
    }
    
    // 输出结果:总长度减去LIS长度
    cout << n - top;
    return 0;
}

 

posted @ 2025-06-15 11:48  CRt0729  阅读(17)  评论(0)    收藏  举报