codeforces : X and Beasts(动态规划)



传送门:  http://codeforces.com/gym/101028/problem/J

【暑期训练正式开始了,加油~~争取区域赛资格,打破去年拿铁的悲剧(>﹏<),希望这个博客也能见证自己的一步步成长】

题意:在一串数中选择出严格递增的子序列,并且使得该数的2的多少幂次之和最小


思路:dp[i][j]表示检索到第i个数时其中最大的数是a[j]时候的取值之和。 如果a[j]<a[i] dp[i][i]=max(dp[i][i],dp[i][j]+foo(a[i])

思路很简单,但是遇到两个大坑点!!(其实就是自己dp没有学好 ==)

j的循环范围是从0开始的,因为不确定是否会取得第一个值,比如dp[3][0]的意思是1,2都不取,从3开始决定取不取,如果而我写的是从1开始也就会自动选取第一个数,15 14可以验证。 (不仔细)

对于当a[j]>=a[i]的时候一定是有dp[i][j]=dp[i-1][j]的,但是考虑到在循环中其实j<i恒成立,那么对于dp[i][i]没有影响,但是如果在普通情况下没有考虑到的话就会因为值没能传递下去而出错 ,通过4 13 8可以验证 在dp[2][1]的时候因为没有传递下去就是0,明显dp[2][1]是通过dp[1][1]传递过来的,因此就是需要将值进行传递的。 

感谢师兄的教导和帮忙仔细查错,想想去年没好好训练辜负了师兄的期望真是很对不起。。。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

int dp[110][110];
int a[110];

int foo(int n)
{
    int cnt=0;
    while(n%2==0)
    {
        n/=2;cnt++;
    }
    return cnt;
}

int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }

        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<i;j++)
            {
                dp[i][j]=dp[i-1][j];
                //if(a[j]>=a[i])
                //    dp[i][j]=dp[i-1][j];
                else dp[i][i]=max(dp[i-1][j]+foo(a[i]),dp[i][i]);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,dp[n][i]);
        printf("%d\n",ans);
    }
    return 0;
}



#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int dp[110][110];int a[110];int foo(int n){ int cnt=0; while(n%2==0) { n/=2;cnt++; } return cnt;}int main(){ int t,n; scanf("%d",&t); while(t--) { memset(dp,0,sizeof(dp)); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { for(int j=0;j<i;j++) { dp[i][j]=dp[i-1][j]; if(a[j]>=a[i]) dp[i][j]=dp[i-1][j]; else dp[i][i]=max(dp[i-1][j]+foo(a[i]),dp[i][i]); } } int ans=0; for(int i=1;i<=n;i++) ans=max(ans,dp[n][i]); printf("%d\n",ans); } return 0;}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值