[入门赛 #21] 星云 hard ver. 解题记录

[入门赛 #21] 星云 hard ver. 解题记录


题意简述

给定 n , k n,k n,k,求在 n n n 位数内,各数位之和不超过 k k k 的正整数的个数。


题目分析

一道很水的数位 DP。
因为 hard ver. 添加了多测,所以暴力是肯定做不了的,这个时候我们升级一下算法,改用使用记忆化搜索的数位 DP 即可(不懂的详见此处)。
站在数位 DP 的角度来看,这道题可以说是很水了。
首先,因为求的是 n n n 位以下的数,所以不需要判断上限。
其次,本题要求的数字要求很简单,只需要记录各数位之和,所以不需要判断前导 0。
本题唯一需要注意的点就是要求的数是正整数,所以在填完数位的时候判断一下是不是 0 即可。


AC Code
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
int dp[105][105],ans;
int T,n,k,a[15];
int dfs(int step,int sum) {//当前填到第step位,数位之和为sum
    if(step>n) {
        if(sum==0) {//填的0
            return 0;
        } else {
            return 1;
        }
    }
    if(dp[step][sum]!=-1) {//记忆化
        return dp[step][sum];
    }
    int ans=0;
    rep(i,0,9) {//因为没有上界,所以直接枚举0~9
        if(sum+i>k) {//这一位如果填i超过了k,那就不填
            continue;
        }
        ans+=dfs(step+1,sum+i);//累加答案
    }
    dp[step][sum]=ans;
    return ans;
}
int solve() {
    memset(dp,-1,sizeof dp);
    return dfs(1,0);
}
signed main() {
    std::cin>>T;
    while(T--) {
        std::cin>>n>>k;
        std::cout<<solve()<<"\n";
    }
    return 0;
}
  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值