数列游戏
★ 输入文件:seqgame.in
输出文件:
seqgame.out
简单对比
时间限制:1 s 内存限制:128 MB
【题目描述】
小M很喜欢找点游戏自娱自乐。有一天,她在纸上写了一串数字:1,1,2,5,4。接着她擦掉了一个1,结果发现剩下1,2,4都在自己所在的位置上,即1在第1位,2在第2位,4在第4位。她希望擦掉某些数后,剩下的数列中在自己位置上的数尽量多。她发现这个游戏很好玩,于是开始乐此不疲地玩起来……不过她不能确定最多能有多少个数在自己的位置上,所以找到你,请你帮忙计算一下!
【输入格式】
第一行为一个数n,表示数列的长度。
接下来一行为n个用空格隔开的正整数,第i行表示数Ai。【输出格式】
一行一个整数,表示擦掉某些数后,最后剩下的数列中最多能有多少个数在自己的位置上,即Ai=i最多能有多少。【样例输入】
5
1 1 2 5 4
【样例输出】
3/**经典的DP问题啊<( ̄︶ ̄)>**/
/********
思路:
对于数列中的每一个数字,有三种可能:
1,这个数字恰好就对应了自己的位置,即a[i]=i;
2,这个数字之前需要删掉几个元素后,才能对应自己的位置,即原来有a[i]<i
3,这个数字无论如何也无法对应自己的位置,即有a[i]>i
因此,我们将数列分为两种状态:
一:一个数字也不删,只有上述第一种可能出现时,才会出现dp++,即当a[i]==i时,dp[i]=dp[i-1]+1,其他情况都是dp[i]=dp[i-1].
二:数列中删了几个数字,
这种情况比较复杂,当计算到第i个数字时,要想使a[i]与i对应,首先a[i]得满足上面的第二种可能,然后从i向前找,比如,
先找到了位置k,我们需要讨论k位置的状态一和状态二的dp大小。
如果,k的状态一的dp加上1且从k到i之间能够删除足够的元素,使得a[i]=i,将此时的dp+1用temp储存,即temp=dp+1;
然后,看看如果k的状态二时的dp,这时,k之前已经删掉了确定数量的元素,如果k与i之前能够删除足够的元素使得a[i]=i,
那将此时的dp+1,与temp进行比较,temp取temp和此时的dp+1的最大值。
k从i-1变到1,最大的temp就是i位置状态二的dp值。
如果,找不到最大的temp,即不存在temp,则使i的状态二dp为一个特殊值,与存在temp的其他位置的dp进行区分。
最后,从1到n,找出各个两种状态下最大的dp值,即所求。
********/
#include<stdio.h>
int main()
{
freopen("seqgame.in","r",stdin);
freopen("seqgame.out","w",stdout);
int Max=0;
int n,i,k;
int dp[1010][2]= {0};
int a[1010]= {0};
scanf("%d",&n);
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
if(a[i]==i)
{
dp[i][0]=dp[i-1][0]+1;
dp[i][1]=-1;
}
else if(a[i]>i)
{
dp[i][0]=dp[i-1][0];
dp[i][1]=-2;
}
else
{
dp[i][0]=dp[i-1][0];
int left,right,temp=0;
for(k=1;k<i;k++)
{
left=k-a[k];
right=i-k-1;
if(dp[k][1]==-1)
{
if(i-k-1>=i-a[i]&&dp[k][0]+1>temp)
temp=dp[k][0]+1;
continue;
}
if(dp[k][1]==-2)
{
if(i-k>=i-a[i]&&dp[k][0]+1>temp)
temp=dp[k][0]+1;
continue;
}
if(left<=i-a[i]&&right+left>=i-a[i])
{
if(dp[k][1]+1>temp)
temp=dp[k][1]+1;
}
}
dp[i][1]=temp;
}
}
for(i=1;i<=n;i++)
{
//printf("%d:\n",i);
//printf("%d %d\n",dp[i][0],dp[i][1]);
if(dp[i][0]>Max)
Max=dp[i][0];
if(dp[i][1]>Max)
Max=dp[i][1];
}
printf("%d\n",Max);
return 0;
}