首页 > 其他分享 >数位DP

数位DP

时间:2023-02-02 17:45:10浏览次数:64  
标签:cnt int sum mask first now DP 数位

数位DP

TODO

题目

CF1073E. Segment Sum

CF1073E. Segment Sum

求 \(L\sim R\) 之间最多不包含 \(K\) 个数码的数的和

\(K\le10,L,R\le10^{18}\)

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int MOD = 998244353;
i64 POW10[19] = {1};
int k;
// 从0位开始算,如 12 中 1位于1位置,2位于0位置
// dp1[i][j] : 第i位选择了状态为j,当前位置及其后的总方案数
// dp2[i][j] : 第i位选择了状态为j,当前位置及其后的总方案和
vector<vector<i64>> dp1(18, vector<i64>(1 << 10, -1));
vector<vector<i64>> dp2(18, vector<i64>(1 << 10, -1));
// 1. now   : 当前选择第几位
// 2. s     : 上界
// 3. mask  : 到当前位置,已经用了哪些数码和个数,first记录出现了哪些数码,second记录出现了多少个数码
// 4. limit : 前面数字是否紧贴上界,即是否有限制
// 5. have  : 前面是否填了数字,即是否为最高位
// 6. 返回值 : first方案数,second总方案和
pair<i64, i64> dfs(int now, const string& s, pair<int, int> mask, bool limit, bool have) {
    // debug(now, s, mask);
    // 已经不符合要求了
    if (mask.second > k) return {0, 0};
    // 从当前位置到最低位置,任意选都不会超过k个,则直接返回(499122177是2在模998244353意义下的乘法逆元)
    if (!limit && now + 1 + mask.second <= k) return {(POW10[now + 1] - !have) % MOD, (POW10[now + 1] - 1) % MOD * POW10[now + 1] % MOD * 499122177 % MOD};
    if (!limit && have && dp1[now][mask.first] != -1) return {dp1[now][mask.first], dp2[now][mask.first]};
    // 选到了最后一位了
    if (now == 0) {
        // 方案不能选多的数码了
        if (mask.second == k) {
            i64 sum = 0;
            i64 cnt = 0;
            int high = limit ? s[now] - '0' : 9;
            for (int i = 0; i <= high; ++i)
                if (mask.first >> i & 1)
                    sum += i, ++cnt;
            if (!limit && have) dp1[now][mask.first] = cnt, dp2[now][mask.first] = sum;
            return {cnt, sum};
        }
        // 在界限范围内任意选
        int high = limit ? s[now] - '0' : 9;
        int low = have ? 0 : 1;
        i64 cnt = high - low + 1;
        i64 sum = (low + high) * cnt / 2;
        if (!limit && have) dp1[now][mask.first] = cnt, dp2[now][mask.first] = sum;
        return {cnt, sum};
    }
    i64 cnt = 0;
    i64 sum = 0;
    // 是最高位,则可以跳过
    if (!have) {
        auto t = dfs(now - 1, s, mask, false, false);
        cnt = (cnt + t.first) % MOD, sum = t.second % MOD;
    }
    int low = have ? 0 : 1;
    int high = limit ? s[now] - '0' : 9;
    for (int i = high; i >= low; --i) {
        int a = mask.first | (1 << i);
        int b = mask.first >> i & 1 ? mask.second : mask.second + 1;
        auto t = dfs(now - 1, s, {a, b}, limit && i == high, true);
        cnt = (cnt + t.first) % MOD;
        sum = (sum + i * POW10[now] % MOD * t.first % MOD + t.second) % MOD;
    }
    if (!limit && have) {
        dp1[now][mask.first] = cnt;
        dp2[now][mask.first] = sum;
    }
    return {cnt, sum};
}
int main() {
    for (int i = 1; i < 19; ++i) POW10[i] = POW10[i - 1] * 10L;
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr), std::cout.tie(nullptr);
    string r;
    i64 _l;
    cin >> _l >> r >> k;
    string l = to_string(_l - 1);
    reverse(l.begin(), l.end());
    reverse(r.begin(), r.end());
    i64 ans1 = dfs(l.length() - 1, l, {0, 0}, true, false).second;
    i64 ans2 = dfs(r.length() - 1, r, {0, 0}, true, false).second;
    cout << (ans2 - ans1 + MOD) % MOD << endl;
}

标签:cnt,int,sum,mask,first,now,DP,数位
From: https://www.cnblogs.com/Cattle-Horse/p/17086813.html

相关文章

  • 【YBT2023寒假Day4 A】网格染色(DP)(矩阵乘法)(DFT)
    网格染色题目链接:YBT2023寒假Day4A题目大意有一个n*3的网格,你可以选恰好m个格子染成黑色。然后对于一个黑点,我们对它周围的\(8\)个点中的一些有限制不能是黑点,......
  • Codeforces1778E 【线性基】【换根DP】
    我,差30秒,就能AC这道题,我知道错哪的时候是倒计时30,不记得优先级想赌一把,因为我没有先写括号的习惯,所以倒计时14的时候交了,然后想改了括号再交一发,改了括号之后,比赛结束了。......
  • C/C++ Socket UDP 广播消息的发送与接收
    C/C++SocketUDP广播消息的发送与接收局域网内全网段广播消息的IP地址为:255.255.255.255,向该IP地址发送广播消息,局域网下的任何网段的客户机都能收到广播。对于发送端,如果......
  • 利用natapp实现TCP、UDP内网穿透
    利用natapp实现TCP、UDP内网穿透natapp官网:​​https://natapp.cn/​​下载:下载下来其实就只有一个文件:首先在natapp官网上注册一个账号,并实名认证,这一步是必须的!然后去购买......
  • Ubuntu错误:E: Could not open lock file /var/lib/dpkg/lock-frontend
    Ubuntu错误:E:Couldnotopenlockfile/var/lib/dpkg/lock-frontendubuntu使用apt下载和更新软件的时候,出现了以下错误:E:Couldnotopenlockfile/var/lib/dpkg/lock-f......
  • 数位DP
    一、常见题面求两个数之间的满足特定条件的数的方案数(提高+/省选-位数为\(10^6\);省选/NOI-位数为\(10^{18}\)or有一些奇奇怪怪的操作)例子:待完善求两个数之间......
  • ThreadPoolExecutor线程池参数设置技巧
    一、ThreadPoolExecutor的重要参数1、corePoolSize:核心线程数*核心线程会一直存活,及时没有任务需要执行*当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建......
  • JavaFX 网格布局 GridPane
    packagefx.com;importjavafx.application.Application;importjavafx.scene.Scene;importjavafx.scene.control.Button;importjavafx.scene.image.Image;importjavafx.......
  • 【YBT2023寒假Day3 A】千与千寻(期望DP)(高斯消元)
    千与千寻题目链接:YBT2023寒假Day3A题目大意一个n*m的平面,你要从(0,0)走到(x,y),你等概率的向上或向右走,然后当你走到(n-1,i)再往右走,就是(0,i),走到(i,m-1)再......
  • AT dp 26 题 题解
    题单:https://www.luogu.com.cn/training/100578#problems嘛虽然是26题,但是简单的题就不想写了...就写绿题及以上的吧目录EIJMOPQRSTUVE对重量dp,设\(dp[i][v]\)表......