• [BZOJ 1799] self 同类分布


    Link:

    BZOJ 1799 传送门

    Solution:

    一句话的题目,看得爽,做得烦

    一般这类和数位相关的都是数位$dp$吧

    不过一开始还是感觉不太可做,毕竟每个数模数不同

    但要发现,模数最高也只可能为$9*19=171$,

    于是只要将数按照他们的数位和(即模数)分类计算即可

    这样便暴力解决了模数不同的问题

    设$dp[sp][sum][rmd][lmt]$表示:

    枚举到第$sp$高位,剩下的数的和位$sum$,此时对$mod$余$rmd$时的方案数(lmt表示是否达到上界)

    感觉数位$dp$还是用记忆化搜索写起来逻辑比较清晰吧

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=175; //n可能为19,sum最大为171 
    int vis[20][MAXN][MAXN][2],mod,dgt,cur,num[20];
    ll a,b,dp[20][MAXN][MAXN][2];
    
    ll dfs(int sp,int sum,int rmd,int lmt)
    {
        if(!sp) return !sum && !rmd;
        if(vis[sp][sum][rmd][lmt]==cur) return dp[sp][sum][rmd][lmt];
        vis[sp][sum][rmd][lmt]=cur;ll ret=0;
        
        int l=max(0,sum-(sp-1)*9),r=min((lmt)?num[sp]:9,sum);
        for(int i=l;i<=r;i++)
            ret+=dfs(sp-1,sum-i,(rmd*10+i)%mod,lmt&(i==num[sp]));
        return dp[sp][sum][rmd][lmt]=ret;
    }
    
    ll solve(ll x)
    {
        ll ret=0;
        for(dgt=0;x;x/=10) num[++dgt]=x%10;
        for(mod=1;mod<=dgt*9;mod++)
            cur++,ret+=dfs(dgt,mod,0,1);
        return ret;
    }
    
    int main()
    {
        scanf("%lld%lld",&a,&b);
        printf("%lld
    ",solve(b)-solve(a-1));
        return 0;
    }

    Review:

    1、少用$memset$,尽量在使用时顺便初始化

    为了区分不同次的调用,可以在每一次调用打上不同的标记

    2、在$dp$时难以处理模数不同的情况

    考虑将数据分类后直接暴力所有可能的模数

    3、$1e18$可能有19位,$MAXN$要设为175

    (一开始扫了一眼题解上$MAXN$为165,以后还是要自己算啊……)

  • 相关阅读:
    WCF 第五章 行为 总结
    WCF 第五章 行为 为服务终结点行为实现一个消息检测器
    WCF 第五章 行为 安全行为
    WCF 第五章 行为 通过配置文件暴露一个服务行为
    静观己心,厚积薄发
    WCF 第五章 行为 实现自定义行为
    创建进程 和 列出所有进程
    递归和分治算法经典题目
    CreateToolhelp32Snapshot
    Base64 编解码C语言实现
  • 原文地址:https://www.cnblogs.com/newera/p/9247114.html
Copyright © 2020-2023  润新知