• [数位DP][AHOI2009] Luogu P4127 同类分布


    
    # include <iostream>
    # include <cstdio>
    # include <cstring>
    # define LL long long
    # define MAXN 22
    
    using namespace std;
    
    int sum, a[MAXN]; 
    // sum 记录各个位数的和
    // a[0]记录当前数的总位数, 后面依次记录位
    LL f[MAXN][MAXN*9][MAXN*9];
    // f[dep][cur][mod] -> 当前 dp 到了第 dep 位, 现在该数的各位之和为 cur, mod 为 % 当前情况的sum值
    
    LL DFS(int dep, int cur, int mod, bool eq){
        if(cur > sum) return 0; // 当总和比当前统计的情况的和还大说明不符合当前的情况
        if(!dep) return mod == 0 && cur == sum; // 如果当前各位数之和与要求的各位数之和相等, 且 mod=0, 就是一个符合条件的答案
        if((!eq)&&(~f[dep][cur][mod])) return f[dep][cur][mod]; // 如果当前不是恰好是答案的询问就可以套记忆化搜索
        // 注意记忆化搜索得到的值都是按照每位的范围为 0~9 计算的, 拿来更新 eq 为真的值就 boom 了
    
        // 若当前的值没有超出边界而且第一次被搜索到
        int lim = (eq? a[dep] : 9); // 确定下一位可以选择的最大值
    
        LL ans = 0;
        for(int i = 0; i <= lim; i++) // 搜索下一位的数位情况, 注意下一位数位从 0 开始
            ans += DFS(dep-1, cur+i, (mod*10+i)%sum, eq&&(i==lim));
        
        if(!eq) // 当前的答案可以用于更新记忆化搜索的值
            f[dep][cur][mod] = ans;
        return ans;
    }
    // dep -> 当前所在的位数
    // cur -> 当前的数位之和
    // mod -> 当前的数 %sum 的值
    // eq  -> 记录上一位填入的数是否和 a[] 中的数相等
    
    LL DP(LL x){
        a[0] = 0;
    
        for(LL i = x; i; i/=10)
            a[++a[0]] = i%10; // 预处理 a[i] 数组
        
        LL ans = 0;
        for(int i = 1; i <= a[0]*9; i++){ // 各个位数之和一定不超过 位数*9
            sum = i; // 统计位数和为 i 的情况
            memset(f, -1, sizeof(f)); // 初始化 f 为(按位)全 1
            ans += DFS(a[0], 0, 0, 1); // DFS 过程
        }
        return ans;    
    }
    
    int main(){
        LL l, r;
        cin>>l>>r;
        cout<<DP(r) - DP(l-1);
        return 0;
    }
    
  • 相关阅读:
    Codeforces Round #573 (Div. 2) C. Tokitsukaze and Discard Items
    Codeforces Round #573 (Div. 2) B
    练习2
    练习1
    上机练习4
    上机练习3
    上机练习1
    JAVA第一次作业
    es document的强制替换、创建、删除
    es 返回定制化的_source数据
  • 原文地址:https://www.cnblogs.com/Foggy-Forest/p/13280575.html
Copyright © 2020-2023  润新知