【sgu390】数位dp

【sgu390】数位dp

 

这题其实就是不断地合并子树,跟前面例一的思想是一样的。

这个打法我觉得非常优美啊(学别人的),为什么要搞lim1和lim2呢?

是因为在区间lim1~lim2之外的都是没有用的,但是我们f[h][sum][rem]里存的是一棵完整的h层的树,所以被lim1和lim2限制的就不存进去了。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const LL N=1100;
LL l,r,K;
struct node{
    LL a,b;
    bool bk;
    node()
    {
        bk=0;a=0;b=0;
    }
}f[20][N][N];
LL dl[20],dr[20];

void mercy(node &x,node y){x.a+=y.a;x.b=y.b;}

node dp(LL h,LL sum,LL rem,LL lim1,LL lim2)
{
    node ans;
    ans.a=0;ans.b=rem;
    if(f[h][sum][rem].bk && !lim1 && !lim2) return f[h][sum][rem];
    if(h==0)
    {
        if(sum+rem>=K) ans.a=1,ans.b=0;
        else ans.a=0,ans.b=sum+rem;
    }
    else 
    {
        LL x=lim1 ? dl[h] : 0;
        LL y=lim2 ? dr[h] : 9;
        for(LL i=x;i<=y;i++)
        {
            mercy(ans,dp(h-1,sum+i,ans.b,(lim1&(i==x)),(lim2&(i==y))));
        }
    }
    if(!lim1 && !lim2) f[h][sum][rem]=ans,f[h][sum][rem].bk=1;
    return ans;
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("me.out","w",stdout);
    scanf("%lld%lld%lld",&l,&r,&K);
    LL x;
    memset(dl,0,sizeof(dl));
    memset(dr,0,sizeof(dr));
    x=0;while(l) {dl[++x]=l%10;l/=10;}
    x=0;while(r) {dr[++x]=r%10;r/=10;}
    printf("%lld\n",dp(18,0,0,1,1).a);
    return 0;
}

 

posted @ 2016-10-17 09:45 拦路雨偏似雪花 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值