序列变换
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1349 Accepted Submission(s): 509
Problem Description
我们有一个数列A1,A2...An,你现在要求修改数量最少的元素,使得这个数列严格递增。其中无论是修改前还是修改后,每个元素都必须是整数。
请输出最少需要修改多少个元素。
请输出最少需要修改多少个元素。
Input
第一行输入一个
T(1≤T≤10)
,表示有多少组数据
每一组数据:
第一行输入一个 N(1≤N≤105) ,表示数列的长度
第二行输入N个数 A1,A2,...,An 。
每一个数列中的元素都是正整数而且不超过 106 。
每一组数据:
第一行输入一个 N(1≤N≤105) ,表示数列的长度
第二行输入N个数 A1,A2,...,An 。
每一个数列中的元素都是正整数而且不超过 106 。
Output
对于每组数据,先输出一行
Case #i:
然后输出最少需要修改多少个元素。
Case #i:
然后输出最少需要修改多少个元素。
Sample Input
2 2 1 10 3 2 5 4
Sample Output
Case #1: 0 Case #2: 1
Source
Recommend
hujie | We have carefully selected several similar problems for you: 5831 5830 5829 5828 5827
解题思路:刚开始简单的以为是求一个最长递增序列长度L,然后用n-L就行了,但是wa了。。。
因为1 2 3 3 4 5这样就是6-5=1,那个多出来的3怎么改都不行的,其实可以这样转化问题,我们把每个数字都对应减去他们的位置编号,比如
1 2 4 6 9 8
-1 -2 -3 -4 -5 -6
这样得到
0 0 1 2 5 2
这样做到底为了什么呢?就是为了排除相等的情况,第i个位置最少要比i+1个位置少1,而i最少要比i+2的位置少2,这样的话,我们只要全部减去自己位置的编号就相当于直接处理好了所有的位置关系,处理好之后我们就直接n-最大非递减子序列就行了还有注意可以用二分贪心的那个方法,普通暴力的方法会超时吧N*N的。总体的时间复杂度是O(n*log(n))的没啥压力。
代码如下:
#include <cstdio>
int a[100010];
int d[100010];
int ans;
int erfen(int x)
{
int l=1,r=ans;
int mid,pos;
while(l<=r)
{
mid=(l+r)/2;
if(d[mid]>a[x])
{
pos=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return pos;
}
int main()
{
int t;
scanf("%d",&t);
int k=1;
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]=a[i]-i;//处理下
}
ans=1;
d[1]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]>=d[ans])//大于等于是因为要求非递减序列
{
ans++;
d[ans]=a[i];
}
else
{
d[erfen(i)]=a[i];
}
}
printf("Case #%d:\n",k++);
printf("%d\n",n-ans);
}
return 0;
}