[COCI2007-2008#3] CUDAK 解题记录

[COCI2007-2008#3] CUDAK 解题记录


题意简述

给定闭区间 [ a , b ] [a,b] [a,b],以及一个整数 s s s,求区间 [ a , b ] [a,b] [a,b] 中有多少个数的各数位之和为 s s s 和最小的满足条件的数。


题目分析

这道题看起来和[入门赛 #21] 星云 hard ver.有点像,所以我们考虑使用数位 DP。
d p s t e p , s u m dp_{step,sum} dpstep,sum 表示当前枚举到第 s t e p step step 位,数位之和为 s u m sum sum 的满足条件的数的个数,因为 s t e p ≤ 15 , s u m ≤ 135 step \leq 15,sum \leq 135 step15,sum135,所以考虑记忆化搜索。
第一个问很水,就是模板,接下来考虑第二个问。(其实也很水)
直接枚举肯定不可能。因为求的数一定在 [ a , b [a,b [a,b] 之间,而这个区间内的数满足单调性,所以可以二分查找,找到最小值。


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
CI N=20;
int a,b,s,num[N],dp[N][150];
int dfs(int step,int sum,int st,int limit) {
    if(step>num[0]) {
        if(sum==s) {
            return 1;
        } else {
            return 0;
        }
    }
    if(!st&&!limit&&dp[step][sum]!=-1) {
        return dp[step][sum];
    }
    int up=limit?num[num[0]-step+1]:9;
    int ans=0;
    rep(i,0,up) {
        if(sum+i>s) {
            break;
        }
        ans+=dfs(step+1,sum+i,st&&i==0,limit&&i==up);
    }
    if(!st&&!limit) {
        dp[step][sum]=ans;
    }
    return ans;
}
int solve(int x) {
    num[0]=0;
    while(x) {
        num[++num[0]]=x%10;
        x/=10;
    }
    mem(dp,-1);
    return dfs(1,0,1,1);
}
signed main() {
    std::cin>>a>>b>>s;
    std::cout<<solve(b)-solve(a-1)<<"\n";
    int l=a,r=b,ans=0;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(solve(mid)-solve(a-1)>0) {
            r=mid-1;
            ans=mid;
        } else {
            l=mid+1;
        }
    }
    std::cout<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值