[好不容易写完了,竟然页面崩溃了一次]数列

【问题描述】

虽然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。

【分析】

f[i][j][0]代表前i个数字擦去j个第i位留下。

f[i][j][1]代表前i个数字擦去j个第i位擦去。

状态转移方程:

f[i][j][0] = max(

  f[i - 1][j][0];

  f[i - 1][j][0]; (i - 1 >= 0)

) + (a[i] == i - j);

f[i][j][1] = max(

  f[i - 1][j - 1][0];

  f[i - 1][j - 1][1]; (i - 1 >= 0;j - 1 >= 0)

)

#include <stdio.h>
#include <iostream>
#define MAXN 1010
using namespace std;
int f[MAXN][MAXN][2],a[MAXN],ans,n;//0不去走 1取走 
bool have[MAXN][MAXN];
void find(int x,int y) {
  if (have[x][y]) return;
  if ((y > x) || (y < 0) || (x < 0)) return;
  have[x][y] = 1;
  find(x - 1,y - 1);
  find(x - 1,y);
  if (x - 1 < 0) return;
  f[x][y][0] = f[x - 1][y][0];
  if ((y - 1 >= 0) && (f[x - 1][y][1] > f[x][y][0]))
    f[x][y][0] = f[x - 1][y][1];
  bool t = (a[x] == (x - y));
  if (t) 
    ++f[x][y][0];
  if (y - 1 >= 0)
    f[x][y][1] = max(f[x - 1][y - 1][0],f[x - 1][y - 1][1]);
}
int main() {
  freopen("sequence.in","r",stdin);
  freopen("sequence.out","w",stdout);
  scanf("%d",&n);
  for (int i = 1;i <= n;++i)
    scanf("%d",&a[i]);
  for (int i = 0;i <= n;++i)
    find(n,i);
  for (int i = 0;i <= n;++i) {
    if (f[n][i][0] > ans)
      ans = f[n][i][0];
    if (f[n][i][1] > ans)
      ans = f[n][i][1];
  }
  printf("%d\n",ans);
  return 0;
}

posted @ 2010-10-08 19:56  Sephiroth.L.  阅读(432)  评论(0编辑  收藏  举报