数列游戏

 数列游戏

★   输入文件: 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值