P2782 友好城市 LIS/nlogn
解题思路
这道题目要求我们通过修改最少的数字,使得给定的序列变成严格递增序列。关键点在于:
-
问题转化:最少修改的数字数量 = 序列总长度 - 最长严格递增子序列(LIS)的长度
-
LIS算法:使用O(nlogn)的贪心+二分法来高效计算最长严格递增子序列
-
严格递增处理:对于每个元素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; }

浙公网安备 33010602011771号