一看这道题就想到DP…但是我错误地认为当时的DP思路有后效性,没有敢打,最后改装了一下最长不降子序列,竟然对了~
      
                
          【问题描述】
          
          虽然msh长大了,但他还是和喜欢找点游戏自娱自乐。有一天,他在纸上写了一串数字:
        
        
          1
        
        
          ,
        
        
          1
        
        
          ,
        
        
          2
        
        
          ,
        
        
          5
        
        
          ,
        
        
          4
        
        
          。
        
      
      
        
          接着他擦掉了一个1,结果发现剩下1,
        
        
          2
        
        
          ,4都在自己所在的位置上,即1在第1位,2在第2位,4在第4位。
        
      
      
        
          他希望擦掉某些数后,剩下的数列中在自己位置上的尽量多。他发现这个游戏很好玩,于是开始乐此不
        
      
      
        
          疲地玩起来……不过他不能确定最多能有多少个数在自己的位置上,所有找到你,请你帮忙计算一下
        
        
          !
        
        
          
          【输入格式】
          
          第1行:1个整数n,表示数列的长度。接下来一行为n个空格隔开的正整数,第i行表示Ai。
          
          【输出格式】
          
          一行一个整数,表示擦掉某些数后,最后剩下的数列中最多能有多少个数在自己的位置上,即Ai
        
        
          =
        
        
          i最
        
      
      
        
          多能有多少。
          
          【样例输入】
          
        
        
          5
        
        
          
        
        
          1
        
        
        
        
          1
        
        
        
        
          2
        
        
        
        
          5
        
        
        
        
          4
        
        
          
          【样例输出】
          
        
        
          3
        
        
          
          【数据范围】
          
          对于20
        
        
          %
        
        
          的数据,n 
        
        
          <=
        
        
        
        
          20
        
        
          ;
          
          对于60
        
        
          %
        
        
          的数据,n 
        
        
          <=
        
        
        
        
          100
        
        
          ;
          
          对于100
        
        
          %
        
        
          的数据,n 
        
        
          <=
        
        
        
        
          1
        
        
          ,
        
        
          000
        
        
          。
        
      
    
  
两种方法。第一种是改装的最长不将子序列。我们将每个数和自己应该在的位置的差记录下来,然后就得到一个新的数列d。我们对这个数列做一下最长不将子序列,但是要注意一点,一定要有数可删。什么意思呢,用数学语言描述就是j-i>d[j]-d[i](j>i),即在i确定的情况下,从i到j之间至少要有d[j]-d[i]个数以保证可以通过删数让j到它自己的位置上。
第二种就是普通的DP。思路、方程、代码详见SephirothLee的《数列》一文,地址 http://www.cnblogs.com/sephirothlee/archive/2010/10/08/1846073.html
参考代码(最长不降子序列):
      
                
           1
        
        
          program
        
        
           sequence;
          
        
        
           2
        
        
        
        
          var
        
        
          
        
        
           3
        
        
           n,max,i,j,l:longint;
          
        
        
           4
        
        
           a,d:
        
        
          array
        
        
          [
        
        
          0
        
        
          ..
        
        
          1001
        
        
          ]
        
        
          of
        
        
           longint;
          
        
        
           5
        
        
           f:
        
        
          array
        
        
          [
        
        
          0
        
        
          ..
        
        
          1001
        
        
          ]
        
        
          of
        
        
           longint;
          
        
        
           6
        
        
           ff:boolean;
          
        
        
           7
        
        
        
        
          begin
        
        
          
        
        
           8
        
        
           readln(n);
          
        
        
           9
        
        
        
        
          for
        
        
           i:
        
        
          =
        
        
          1
        
        
        
        
          to
        
        
           n 
        
        
          do
        
        
          
        
        
          10
        
        
        
        
          begin
        
        
          
        
        
          11
        
        
           read(a[i]);
          
        
        
          12
        
        
           d[i]:
        
        
          =
        
        
          i
        
        
          -
        
        
          a[i]; 
        
        
          //
        
        
          不能写成i
        
        
          -
        
        
          a[i],否则处理方法不同
          
        
        
          13
        
        
        
        
          end
        
        
          ;
          
        
        
          14
        
        
        
        
          for
        
        
           i:
        
        
          =
        
        
          n
        
        
          -
        
        
          1
        
        
        
        
          downto
        
        
        
        
          1
        
        
        
        
          do
        
        
          
        
        
          15
        
        
        
        
          for
        
        
           j:
        
        
          =
        
        
          i
        
        
          +
        
        
          1
        
        
        
        
          to
        
        
           n 
        
        
          do
        
        
          
        
        
          16
        
        
        
        
          if
        
        
          (d[i]
        
        
          >=
        
        
          0
        
        
          )
        
        
          and
        
        
          (d[j]
        
        
          >=
        
        
          0
        
        
          )
        
        
          and
        
        
          (d[i]
        
        
          <=
        
        
          d[j])
        
        
          then
        
        
        
        
          //
        
        
          如果是负数,就不能通过删数归位
          
        
        
          17
        
        
        
        
          if
        
        
           d[j]
        
        
          -
        
        
          d[i]
        
        
          <=
        
        
          j
        
        
          -
        
        
          i
        
        
          -
        
        
          1
        
        
        
        
          then
        
        
        
        
          //
        
        
          关键的限制条件
          
        
        
          18
        
        
        
        
          if
        
        
          (d[i]
        
        
          <
        
        
          i)
        
        
          and
        
        
          (d[j]
        
        
          <
        
        
          j)
        
        
          then
        
        
          
        
        
          19
        
        
        
        
          if
        
        
           f[j]
        
        
          +
        
        
          1
        
        
          >
        
        
          f[i] 
        
        
          then
        
        
           f[i]:
        
        
          =
        
        
          f[j]
        
        
          +
        
        
          1
        
        
          ;
          
        
        
          20
        
        
           ff:
        
        
          =
        
        
          false;
          
        
        
          21
        
        
        
        
          for
        
        
           i:
        
        
          =
        
        
          1
        
        
        
        
          to
        
        
           n 
        
        
          do
        
        
          
        
        
          22
        
        
        
        
          if
        
        
           max
        
        
          <
        
        
          f[i] 
        
        
          then
        
        
          
        
        
          23
        
        
        
        
          begin
        
        
          
        
        
          24
        
        
           ff:
        
        
          =
        
        
          true;
          
        
        
          25
        
        
           l:
        
        
          =
        
        
          i;
          
        
        
          26
        
        
           max:
        
        
          =
        
        
          f[i];
          
        
        
          27
        
        
        
        
          end
        
        
          ;
          
        
        
          28
        
        
          if
        
        
          (d[l]
        
        
          >
        
        
          l)
        
        
          or
        
        
          (d[l]
        
        
          <
        
        
          0
        
        
          )
        
        
          then
        
        
           dec(max); 
        
        
          //
        
        
          一定要保证第一个数可以归位
          
        
        
          29
        
        
        
        
          if
        
        
           ff 
        
        
          then
        
        
           writeln(max
        
        
          +
        
        
          1
        
        
          ) 
        
        
          //
        
        
          加上最后面的一个
          
        
        
          30
        
        
        
        
          else
        
        
           writeln(
        
        
          '
        
        
          0
        
        
          '
        
        
          ); 
        
        
          //
        
        
          如果根本就没有,则输出0
          
        
        
          31
        
        
        
        
          end
        
        
          .
        
      
    
  (saltless原创,转载请注明出处)

