HDU:5256 序列变换(LIS-n*logn解法+思维+技巧)

40 篇文章 0 订阅
24 篇文章 0 订阅

序列变换

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(1T10) ,表示有多少组数据

每一组数据:

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

第二行输入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
 

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;
} 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值