首页 > 其他分享 >数位DP

数位DP

时间:2023-02-04 00:55:35浏览次数:47  
标签:int mask first i64 second 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) {
    // 每个位置的数都已经确定
    if (now == -1) return {mask.second <= k, 0};
    // 已经不符合要求了
    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]};
    i64 cnt = 0, 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;
}

标签:int,mask,first,i64,second,now,DP,数位
From: https://www.cnblogs.com/egg-pain/p/17090771.html

相关文章

  • IIS WordPress 单站点,多站点 中文URL乱码和重定向多次问题解决方法
    前提是需要安装IISURL重写组件(安装方法这里不说明,搜一下资料就有)1、站点网站根目录新增一个chineseurl.php文件用来处理中文url问题<?php//IISMod-Rewriteif(is......
  • WordPress4.6任意命令执行漏洞
    前言WordPress是一种使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站。也算是一个内容管理系统(CMS)环境搭建docker环境(......
  • 树形dp
    大佬博客由于树形dp种类繁多,而且大佬博客中总结的很好,这里我就只记录下我写到的树形dp《F-Components》  简单的来说就是:给一颗有n个节点的树,因......
  • 数位DP
    数位DPTODO补充数位\(DP\)概念等补充题目分析及过程增加题目题目CF1073E.SegmentSumCF1073E.SegmentSum求\(L\simR\)之间最多不包含\(K\)个数码的......
  • 【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有一些奇奇怪怪的操作)例子:待完善求两个数之间......