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

【问题描述】

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

}



你可能感兴趣的:(页面)