序列变换
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
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
思路:这道题其实有个巧妙的做法,我们假设有一段序列di.......dj(j>i),假设要改变di和dj之间的数,那么必有dj-di>=j-i,因为di后的第一个数最小也要是di+1,第二个最小也要是di+2.......,所以肯定要有dj最小为di+j-i,即dj-di>=j-i,移项可得dj-j>=di-i;所以可知我们所求就是原先序列-它的序号所成新的数列的一个最长上升子序列(非严格的),
答案就是n-最长上升子序列。
答案就是n-最长上升子序列。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int a[100005],b[100005];
int len;
int max(int x,int y)
{
if(x>y)
return x;
return y;
}
int f(int x)//二分优化
{
int l=1,r=len,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(x>=b[mid])//非递减
l=mid+1;
else
r=mid-1;
}
return l;
}
int main()
{
int t,c=1;
scanf("%d",&t);
while(t--)
{
printf("Case #%d:\n",c++);
int n,i,j;
len=0;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
a[i]=a[i]-i;//这个地方把问题转化为最大非递减子序列
}
int maxn=0;
for(i=0;i<n;i++)
{
int k=f(a[i]);
b[k]=a[i];
len=max(len,k);
}
//printf("*%d\n",len);
printf("%d\n",n-len);
}
return 0;
}