P1028 [NOIP2001 普及组] 数的计算 题解

好吧,这道题有两种解法

第一种估计是大家一下子就想到的:

暴力递归!!(很明显不是正解)

粘一个我的代码

#include<cstdio>
using namespace std;
int n,cnt=1;
void func(int x){
    for(int i=1;i<=x/2;i++){
        cnt++;
        func(i);
    }
}
int main(){
    scanf("%d",&n);
    func(n);
    printf("%d\n",cnt);
}

这个递归大概能骗过n=500,然而题目中是n<=1000 所以正解肯定不是暴力

正解其实是递推(也可以说是简单DP)

先粘个代码再解释

#include<cstdio>
using namespace std;
int main(){
    int n,cnt=1,i,f[1010];
    f[0]=f[1]=1;
    scanf("%d",&n);
    for(i=2;i<=n;i++){
        if(i%2==0){
            f[i]=f[i-1]+f[i/2];
        }else{
            f[i]=f[i-1];
        }
    }
    printf("%d\n",f[n]);
}

在打代码之前,我们不妨手动模拟一下

n=0,n=1时,答案显然是1
n=2, ans=2;    n=3,ans=2
n=4,ans=4;    n=5,ans=4
n=6,ans=6;    n=7,ans=6

相信大家也发现了,2n与2n+1(n为非负整数)的答案是一样的 这就是第一个规律

然后我们以n=8为例,手动模拟一下

一共有10组解

8 1 8 2 8 3 8 4 8

1 2 8 1 3 8 1 4 8 2 4 8

1 2 4 8

我打出的东西很像一棵搜索树。。。

当我们把8和8下面的左三棵子树放在一起(即8和下面三列),并将所有的8都改成7,我们能发现,我们得到了n=7时的所有解;

我们再把最右端的子树(即剩下的部分)中的所有8删去,我们得到了n=4时的所有解

就这样,我们可以得到一个递推式,

    f(n)=f(n-1)                //7=8-1

        +f(n/2)                //4=8/2

再结合之前发现的规律

就能得到:

n%2==0时
    f(n)=f(n-1)+f(n/2)
n%2==1时
    f(n)=f(n-1)
然后问题就迎刃而解啦
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值