• [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,以后还是要自己算啊……)

  • 相关阅读:
    项目定义
    面向对象和面向过程
    基本数据类型
    关键字未理解
    面向对象3大特质5大原则未理解
    什么是项目未定义
    项目立项
    方法重载与重写
    停止oracle正在执行的JOB
    实验一密码引擎商用密码算法实现1
  • 原文地址:https://www.cnblogs.com/newera/p/9247114.html
Copyright © 2020-2023  润新知