• [BZOJ1799][AHOI2009]同类分布(数位DP)


    1799: [Ahoi2009]self 同类分布

    Time Limit: 50 Sec  Memory Limit: 64 MB
    Submit: 1635  Solved: 728
    [Submit][Status][Discuss]

    Description

    给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。

    Input

    Output

    Sample Input

    10 19

    Sample Output

    3

    HINT

    【约束条件】1 ≤ a ≤ b ≤ 10^18

    Source

    设计好状态后就是比较简单的数位DP了,实际上数位DP就是记录了中间状态的搜索。

    首先枚举各个位上的数之和为mod,然后它的贡献是所有数位和为mod且这个数本身%mod=0的数的个数,设f[i][sm][md]表示考虑从高到低前i位,前i位的数位和为sm,数本身%mod=md的数的合法个数,最终贡献为f[len][0][0]。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define rep(i,l,r) for (ll i=l; i<=r; i++)
    typedef long long ll;
    using namespace std;
    
    ll L,R,ans,mod,a[21],P[21],f[21][170][170];
    
    ll dfs(ll x,ll sm,ll md,ll lim){
        if (!x) return (sm==mod) && !md;
        if (!lim && ~f[x][sm][md]) return f[x][sm][md];
        ll res=0;
        rep(j,0,(lim?a[x]:9)) res+=dfs(x-1,sm+j,(j*P[x-1]+md)%mod,lim && j==a[x]);
        if (!lim) f[x][sm][md]=res;
        return res;
    }
    
    ll calc(ll n){
        if (!n) return 0;
        memset(f,-1,sizeof(f));
        P[0]=1; rep(i,1,18) P[i]=(P[i-1]*10)%mod;
        ll len=0; while (n) a[++len]=n%10,n/=10;
        return dfs(len,0,0,1);
    }
    
    int main(){
        freopen("bzoj1799.in","r",stdin);
        freopen("bzoj1799.out","w",stdout);
        scanf("%lld%lld",&L,&R);
        for (mod=1; mod<=162; mod++) ans+=calc(R)-calc(L-1);
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    学习网站
    Windows下python安装运行
    Python学习
    ES学习
    Eclipse安装lombok及常用注解
    Spark学习资料
    Spring Cloud学习资料
    使用Excel过滤重复数据
    Excel根据字符串截取单元格部分内容
    Spring中@Transactional(rollbackFor = Exception.class)的作用
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8649316.html
Copyright © 2020-2023  润新知