Jason的特殊爱好 [FZU 2113]

本文提供了一道FZU 2113的数位DP算法题解,通过枚举1的个数,并利用递归函数计算区间[L, R]内数字中1出现的总次数。代码实现简洁高效,适用于ACM竞赛等场景。

http://acm.fzu.edu.cn/problem.php?pid=2113

枚举1的个数,ans=ans+i*dfs();

View Code
const int MM = 11111;
typedef __int64 int64;
#define debug puts("wrong")
int cnt, num[MM];
int64 dp[20][20][20],L,R;

int64 dfs(int le,int sum,int s,bool less) { 
    if(le==-1) return sum==s;
    if(!less && dp[le][sum][s]!=-1) return dp[le][sum][s]; 
    int64 res=0; int d, e=less?num[le]:9;
    for(d=0;d<=e;d++) {
        if(d==1) res+=dfs(le-1,sum,s+1,less&&d==e);
        else res+=dfs(le-1,sum,s,less&&d==e);
    }
    if(!less) dp[le][sum][s]=res;
    return res;
}

int64 cal(int64 x) {
    for(cnt=0; x ;num[cnt++]=x%10,x/=10);
    int64 ans=0;
    for(int i=1;i<=cnt;i++) ans=ans+i*dfs(cnt-1,i,0,true);
    return ans;
}
void solve() {
    printf("%I64d\n",cal(R)-cal(L-1));
}

int main() {
    memset(dp,-1,sizeof(dp));
    while(scanf("%I64d%I64d",&L,&R)!=EOF) solve();
    return 0;
}

 

转载于:https://www.cnblogs.com/zhang1107/archive/2013/05/03/3056385.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值