序列变换 HDU - 5256

序列变换 HDU - 5256

题目链接

题目

我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增。其中无论是修改前还是修改后,每个元素都必须是整数。
请输出最少需要修改多少个元素。

input

第一行输入一个T(1≤T≤10),表示有多少组数据

每一组数据:

第一行输入一个N(1≤N≤105),表示数列的长度

第二行输入N个数A1,A2,...,An。

每一个数列中的元素都是正整数而且不超过106。

output

对于每组数据,先输出一行

Case #i:

然后输出最少需要修改多少个元素。

Sample Input

2
2
1 10
3
2 5 4

Sample Output

Case #1:
0
Case #2:
1

分析

一开始很容易就想到 \(\mathrm{LIS}\) 。先算出 \(\mathrm{LIS}\) 的长度,然后序列总长度减去 \(\mathrm{LIS}\) 的长度就行了。

但是隐隐间觉得有点不对,留意到题目中的严格递增,就想到了如果连续几个都是相同的怎么办。然后就举出了反例。

例如:1 2 2 2 3 。这个序列的 \(\mathrm{LIS}\) 为 1 2 3。按照上面的的方法算出的答案是 2 。但实际上,我们要修改成 1 2 3 4 5。要修改的个数为 3。

但我们还是想要往 \(\mathrm{LIS}\) 上靠,仔细分析一下,我们修改后的整个数组要满足如下的条件:
\[
arr[i + 1] \ge arr[i] + 1
\]
怎么往 \(\mathrm{LIS}\) 上靠呢?\(\mathrm{LIS}\) 最后的式子是不是要满足:
\[
a[i + 1] \ge a[i]
\]
第一个式子中的 \(1\) 是不是有点碍事,留意到两边其实可以做一个操作:
\[
arr[i + 1] - i - 1 \ge arr[i] - i
\]
两边都可以减去一个 \(i\) , 那么就可以转化到 \(\mathrm{LIS}\) 的做法了。

再留意到 \(n \le 10^5,T \le 10\) , \(O(n^2)\) 的复杂度肯定是接受不了,要对朴素的做法进行一些优化。

其实也是一个贪心的做法。我们可以去维护这样一个 \(dp\) 数组。不妨设 \(len\) 为 \(dp\) 数组的长度。在遍历数组 \(arr\) 的时候,有两种情况:

  1. \(arr[i] \ge dp[len - 1]\),把 \(arr[i]\) 加到 \(dp\) 数组的结尾。
  2. \(arr[i] < dp[len - 1]\),二分查找 \(dp\) 数组里,第一个大于 \(arr[i]\) 数字,然后替换成 \(arr[i]\)。

然后,最后 \(len\) 就是 \(\mathrm{LIS}\) 的长度。

看得出来,数组 \(dp\) 本身就在维护一个尽可能长的上升序列,第一个操作很好理解,那么对于第二个操作,由贪心我们可以知道,如果有几个序列,那么序列末尾的数字越小,那么它能成为 \(\mathrm{LIS}\) 的概率越大?所以第二个操作就是不断地在保证它在成为 \(\mathrm{LIS}\)。如果但是如果替换的不是最后一个呢?由于是替换,不是增加或者减小,所以这对于最后的结果并没有影响,所以替换前面的数字并没有影响。(这造成了 \(dp\) 数组并不是 \(\mathrm{LIS}\) )。

所以用二分就能把 \(\mathrm{LIS}\) 优化到 \(O(n \log n)\)。

代码

#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-x))
#define mem(i, a) memset(i, a, sizeof(i))
#define sqr(x) ((x)*(x))
typedef long long ll;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 7;
using namespace std;
int arr[maxn], dp[maxn];
int main(void){
#ifdef ljxtt
freopen("data.in", "r", stdin);
#endif
    int T; scanf("%d", &T);
    int cases = 1;
    while(T--){
        int n; scanf("%d", &n);
        for(int i = 0; i < n; i++){
            scanf("%d", &arr[i]);
            arr[i] -= i;
        }
        int len = 0;
        dp[0] = arr[0];
        for(int i = 1; i < n; i++){
            if(arr[i] >= dp[len])
                dp[++len] = arr[i];
            else
                *upper_bound(dp, dp + len + 1, arr[i]) = arr[i];
        }
        printf("Case #%d:\n%d\n", cases++, n - len - 1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ljxtt/p/12222906.html

时间: 2024-10-12 20:26:25

序列变换 HDU - 5256的相关文章

hdu 5256 序列变换 (LIS变形)

序列变换 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 519    Accepted Submission(s): 245 Problem Description 我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元素都必须是整数. 请输出最少需要修改多少个元素.

LIS 2015百度之星初赛2 HDOJ 5256 序列变换

题目传送门 1 /* 2 LIS(非严格):首先我想到了LIS,然而总觉得有点不对:每个数先减去它的下标,防止下面的情况发生:(转载) 3 加入序列是1,2,2,2,3,这样求上升子序列是3,也就是要修改2个,但是中间的两个2,变化范围又不能超过(1,3) 4 那么这样求的也就不对,但是减掉之后,相当于给中间重复的数留下了修改的空间 5 解释下为什么可以减而保持正确性:因为题目所求时严格递增,假设是2,3, 4,那么变成1, 1, 1,所以在LIS里非严格递增就可以了 6 这也是为什么要在upp

2015年百度之星初赛(1) --- C 序列变换

序列变换 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 158    Accepted Submission(s): 83 Problem Description 给定序列$A = \{A_1, A_2,...,A_n\}$, 要求改变序列A中的某些元素,形成一个严格单调的序列B(严格单调的定义为:$B_i < B_{i+1}, 1 \

2015百度之星初赛1 序列变换

序列变换 Accepts: 720 Submissions: 3074 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description 给定序列A={A1,A2,...,An}, 要求改变序列A中的某些元素,形成一个严格单调的序列B(严格单调的定义为:Bi<Bi+1,1≤i<N). 我们定义从序列A到序列B变换的代价为cost(A,B)=max(|Ai?Bi

Linux工具开发[02]---编程实现对输入字符序列变换(编码/加密/散列)方式的智能判定

怎样简单实现一个能够智能判定输入字符序列变换方式的小程序 本文由CSDN-蚍蜉撼青松 [主页:http://blog.csdn.net/howeverpf]原创,转载请注明出处! 问题描写叙述: 在分析网络数据包或者研究安全问题时.经常会遇到变换后的字符序列.而是否能准确识别密文的变换算法,对进一步的分析工作非常关键. 经常使用的变换算法包含但不限于:Base64.URL编码.HTML编码.MD5散列.DES加密.RSA加密等. 要求: 1)在理解算法原理及密文特点的基础上.使用随意编程语言实现

Linux工具开发---2编程实现对输入字符序列变换(编码/加密/散列)方式的智能判定

如何简单实现一个可以智能判定输入字符序列变换方式的小程序 本文由CSDN-蚍蜉撼青松 [主页:http://blog.csdn.net/howeverpf]原创,转载请注明出处! 问题描述: 在分析网络数据包或者研究安全问题时,经常会遇到变换后的字符序列.而能否准确识别密文的变换算法,对进一步的分析工作很关键.常用的变换算法包括但不限于:Base64.URL编码.HTML编码.MD5散列.DES加密.RSA加密等.要求: 1)在理解算法原理及密文特点的基础上,使用任意编程语言实现,当输入一段密文

二分搜索 2015百度之星初赛1 1003 序列变换

题目传送门 1 /* 2 二分搜索:在0-1e6的范围找到最小的max (ai - bi),也就是使得p + 1 <= a[i] + c or a[i] - c 3 比赛时以为是贪心,榨干智商也想不出来:( 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 #include <iostream> 10 using

序列变换(Lis变形)

序列变换 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1200    Accepted Submission(s): 448 Problem Description 我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增.其中无论是修改前还是修改后,每个元素都必须是整数. 请输出最少需要修改多少个元素

BC 2015年百度之星程序设计大赛 - 初赛(1)(序列变换-二分答案贪心)

序列变换 Accepts: 816 Submissions: 3578 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description 给定序列A={A 1 ,A 2 ,...,A n } , 要求改变序列A中的某些元素,形成一个严格单调的序列B(严格单调的定义为:B i <B i+1 ,1≤i<N ). 我们定义从序列A到序列B变换的代价为cost(A,B