数列(sequence)
【问题描述】
虽然msh长大了,但她还是很喜欢找点游戏自娱自乐。有一天,她在纸上写了一串数字:1,1,2,5,4。接着她擦掉了一个1,结果发现剩下1,2,4都在自己所在的位置上,即1在第1位,2在第2位,4在第4位。她希望擦掉某些数后,剩下的数列中在自己的位置上的数尽量多。她发现这个游戏很好玩,于是开始乐此不疲地玩起来……不过她不能确定最后能有多少个数在自己的位置上,所以找到你,请你帮忙计算一下!
【输入】
第一行为一个数n ,表示数列的长度。
接下来一行为n个用空格隔开的正整数,第i行表示数Ai 。
【输出】
一行一个整数,表示擦掉某些数后,最后剩下的数列中最多能有多少个数在自己的位置上,即Ai=i最多能有多少。
【样例】
Sequence.in
5
1 1 2 5 4
Sequence.out
3
数据规模
对于20%的数据,n≤20;
对于60%的数据,n≤100;
对于100%的数据,n≤1000。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
初看本题,想到的是动归;
于是有了初步的动归方程:
f[i][j]=max(f[i-1][j],f[i-1][j-1])
可是又看了一遍题目发现这题后效性
于是改变方案用LCIS,但是事实证明这样是不行的
看过题解后,发现了一个问题……我所理解的后效性一直以来都是有问题的
后效性,即未来的状态对当前已决策的状态的影响;
可是,我一直以为,后效性是,当前状态对未来状态的影响。
(哎……得亏是现在发现了,要是考试的时候还不知道对后效性理解有问题就惨了……)
既然无后效性,且满足最有子结构,我们就可已得到一个动归方程了:
f[i][j]=max(f[i-1][j]+a,f[i-1][j-1]) (if (i-j==a[i])a=1;else a=0;)
f[i][j]表示前i位,去除j个数
++++++++++++++++++++++++代码入下+++++++++++++++++++++++++++++++++
<span style="font-family:Comic Sans MS;">#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n=5,a[10050],b[10050],z,f[1050][1050];
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i]; z=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=n;j++)
f[i][j]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=n;j++)
{
if(i-j==a[i]&&a[i]!=0)f[i][j]=max(f[i-1][j]+1,f[i-1][j-1]);
else f[i][j]=max(f[i-1][j],f[i-1][j-1]);
z=max(z,f[i][j]);
}
cout<<z;
return 0;
}</span>