欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

腾讯2018秋招正式笔试题目——拼凑硬币

程序员文章站 2022-06-09 11:12:10
...

时间限制:(每个case)2s      空间限制:128MB

小Q十分富有,拥有非常多的硬币,小Q拥有的硬币是有规律的,对于所有的非负整数K,小Q恰好各有两个面值为2^K的硬币,所以小Q拥有的硬币就是1,1,2,2,4,4,8,8,…。小Q有一天去商店购买东西需要支付n元钱,小Q想知道有多少种方案从他拥有的硬币中选取一些拼凑起来恰好是n元(如果两种方案某个面值的硬币选取的个数不一样就考虑为不一样的方案)。

输入:

输入包括一个整数n(1<=n<=10^18),表示小Q需要支付多少钱。注意n的范围。

输出:

输出一个整数,表示小Q可以拼凑出n元钱放的方案数。

【请注意:javascrip语言不支持调试,请同学们优先考虑使用其他语言,谢谢】

样例输入:6

样例输出:3


数位dp,将n表示成二进制,从为1的位置向后转移。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=200+10;
int dp[maxn];
int nxt[maxn],pos[maxn];
int inx,res;
int dfs(int x){
    if(x==-1)return 1;
    if(dp[x]!=0)return dp[x];
    dp[x]+=dfs(nxt[x]);
    for(int i=1;i<x;i++){
        if(pos[i]==1)continue;
        dp[x]+=dfs(nxt[i]);
    }
    return dp[x];
}
signed main(){
    int n;
    scanf("%lld",&n);
    res=-1;
    while(n){
        pos[++inx]=n%2;
        nxt[inx]=res;
        if(n&1)res=inx;
        n/=2;
    }
    printf("%lld\n",dfs(inx));
    return 0;
}

在别人博客中看见了更加简单的方法,用位运算+分治,将0看成是用了0次或者2次,1表示自己用了一次或者后面用了两次。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn=200+10;
int solve(int n){
    if(n==0)return 0;
    if(n==1)return 1;
    if(n==2)return 2;

    if(n&1){
        return solve(n>>1);
    }
    return solve(n>>1)+solve((n-2)>>1);
}
signed main(){
    int n;
    scanf("%lld",&n);
    printf("%lld\n",solve(n));
    return 0;
}