HDU 5256

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
 
解题思路:
  不难理解,求 a[i]-i 的最长非递减子序列长度 len ,然后 n-len 就是答案了;
  以下有两份代码;
  代码一:
    二分法,打模板即可;时间复杂度O(nlog(n))
  代码二:
    树状数组,前缀最大值的应用。 时间复杂度也是 O(nlog(n))
    回想求LIS的动态规划过程 dp[i]=max(dp[j]); (i>j&&h[j]<h[i])
    利用树状数组的性质: dp[i]=query(a[i]);
    但这道题上还有很多问题,比如负数的存在,应此需要离散化;
    应注意离散化后再去标记最大值,WA了好久好久..     
 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 int c[1000000],n,t,len,a;
 5 int find(int l,int r,int num){
 6     while(l<=r){ int mid=(l+r)>>1; if(c[mid]<=num) l=mid+1; else r=mid-1; }
 7     return l;
 8 }
 9 int main(){
10     scanf("%d",&t);
11     for(int k=1;k<=t;k++){
12         printf("Case #%d:
",k);
13         scanf("%d",&n);
14         len=1; memset(c,0,sizeof(c));
15         for(int i=1;i<=n;i++){
16             scanf("%d",&a);
17             if(i==1){ c[len]=a-i; continue;    }
18             int pos=find(1,len,a-i);
19             c[pos]=a-i;
20             if(len<pos) len=pos;
21         }    printf("%d
",n-len);
22     } return 0;
23 }
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 #define N 1000000+5
 6 int c[N],a[N],b[N],n,t,nmax;
 7 void modify(int x,int num){while(x<=nmax)c[x]=max(c[x],num),x+=x&-x;}
 8 int query(int x){int s=0;while(x>0)s=max(c[x],s),x-=x&-x;return s;}
 9 int main(){
10     scanf("%d",&t);
11     for(int k=1;k<=t;k++){
12         printf("Case #%d:
",k);
13         scanf("%d",&n);
14         memset(c,0,sizeof(c)); nmax=0;
15         for(int i=0;i<n;i++){
16             scanf("%d",&a[i]);
17             a[i]-=i; b[i]=a[i]; 
18         } 
19         sort(b,b+n); 
20         int size=unique(b,b+n)-b;//离散化 
21         for(int i=0;i<n;i++){
22             a[i]=lower_bound(b,b+size,a[i])-b+1;
23             nmax=max(a[i],nmax);//离散化以后再去标记最大值 
24         } 
25         for(int i=0;i<n;i++)modify(a[i],query(a[i])+1);//前缀最大值+1 
26         printf("%d
",n-query(nmax));
27     } return 0;
28 }
我自倾杯,君且随意
原文地址:https://www.cnblogs.com/nicetomeetu/p/5167903.html