[好不容易写完了,竟然页面崩溃了一次]数列
【问题描述】
虽然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; }