您的位置:首页 > 其它

HDU:5773 The All-purpose Zero(LIS-n*logn解法+思维+技巧)

2016-08-13 10:29 525 查看

The All-purpose Zero

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1618    Accepted Submission(s): 774


[align=left]Problem Description[/align]
?? gets an sequence S with n intergers(0 < n <= 100000,0<= S[i] <= 1000000).?? has a magic so that he can change 0 to any interger(He does not need to change all 0 to the same interger).?? wants you to help him to find out
the length of the longest increasing (strictly) subsequence he can get.
 

[align=left]Input[/align]
The first line contains an interger T,denoting the number of the test cases.(T <= 10)

For each case,the first line contains an interger n,which is the length of the array s.

The next line contains n intergers separated by a single space, denote each number in S.

 

[align=left]Output[/align]
For each test case, output one line containing “Case #x: y”(without quotes), where x is the test case number(starting from 1) and y is the length of the longest increasing subsequence he can get.
 

[align=left]Sample Input[/align]

2
7
2 0 2 1 2 0 5
6
1 2 3 3 0 0

 

[align=left]Sample Output[/align]

Case #1: 5
Case #2: 5

HintIn the first case,you can change the second 0 to 3.So the longest increasing subsequence is 0 1 2 3 5.

 

[align=left]Author[/align]
FZU
 

[align=left]Source[/align]
2016 Multi-University Training
Contest 4
 

[align=left]Recommend[/align]
wange2014   |   We have carefully selected several similar problems for you:  5831 5830 5829 5828 5827
 
题目大意:给了你一个序列,其中0可以修改成任意数字(包括负数),问修改之后最长子序列长度为多少。
解题思路:可以转化成任意整数,包括负数,显然求LIS时尽量把0都放进去必定是正确的。因此我们可以把0拿出来,对剩下的做O(nlogn)的LIS,统计结果的时候再算上0的数量。为了保证严格递增,我们可以将每个权值S[i]减去i前面0的个数,再做LIS,就能保证结果是严格递增的。(注意全0的时候特判下,这个方法不符合)
代码如下:
 
#include <cstdio>
int b[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]>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);
int num=0;//0的数量
int hao=0;//新数组角标
for(int i=1;i<=n;i++)//输入数据的同时构建新数组
{
int x;
scanf("%d",&x);
if(x==0)
{
num++;
}
else
{
hao++;
b[hao]=x-num;
}
}
if(hao==0)//全0的时候特判一下
{
printf("Case #%d: ",k++);
printf("%d\n",n);
continue;
}
d[1]=b[1];
ans=1;//记录LIS长度
for(int i=2;i<=hao;i++)
{
if(b[i]>d[ans])
{
ans++;
d[ans]=b[i];
}
else
{
d[erfen(b[i])]=b[i];
}
}
printf("Case #%d: ",k++);
printf("%d\n",ans+num);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  LIS 二分 优化 思维 技巧