首页 > 其他分享 >P10958 启示录 解题报告

P10958 启示录 解题报告

时间:2024-09-01 11:36:19浏览次数:4  
标签:P10958 num int ll pos 启示录 flag 解题 limit

更好的阅读体验

用记忆化搜索写数位 dp 真的很好写!

题目传送门

题目大意:

\(T\) 组数据,每次询问第 \(x\) 个含有至少 \(3\) 个连续 \(6\) 的数是什么。

思路:

考虑数位 dp。

一般数位 dp 问题有两种常见形式:

  1. 询问 \([l, r]\) 内有多少个符合条件的数;
  2. 询问满足条件的第 \(k\) 大(小)的数是什么。

很显然这道题是第二种形式。

首先问题 \(1\) 很简单,那我们考虑将第二个问题转化成第一个问题来做。

因为答案具有单调性,于是可以二分判定。

每次二分到一个值 \(mid\),计算 \([1, mid]\) 的魔鬼数个数,若大于等于 \(x\),则说明所求在 \(mid\) 左侧,否则在 \(mid\) 右侧。

接着考虑问题 \(1\),这里采用记忆化搜索的方式,注释在代码中。

//pos 记录当前填到了哪一位,cnt 记录当前末尾有几个连续的 6,flag 记录当前数是否满足条件
//limit 记录当前有没有顶上界
//因为这道题有没有前导零无影响,遂不记录
int dfs(int pos, int cnt, bool flag, bool limit) {
    //边界,若填完了就检查一下是否符合条件
    if(pos < 0) return flag;
    //若不顶上界就记忆化,因为顶上界是特殊情况,满足条件的数可能和普通情况不同
    if(!limit && f[pos][cnt][flag] != -1) return f[pos][cnt][flag];
    //看一下当前这位需不需要顶上界,若前面填的数都是贴着上界的,这一位最多只能填到 num[pos],否则不受限
    int mx = (limit ? num[pos] : 9);
    int res = 0;
    //枚举第 pos 位填什么
    for(int i = 0; i <= mx; i++) {
        //处理连续的 6
        int ncnt;
        if(i == 6) ncnt = cnt + 1;
        else ncnt = 0;
        res += dfs(pos - 1, ncnt, flag || (ncnt >= 3), limit && (i == num[pos]));
    }
    //若不顶上界就记忆化
    if(!limit) f[pos][cnt][flag] = res;
    return res;
}

这里我直接把二分值域拉满了,但是实测发现第 \(50000000\) 个魔鬼数只有 \(6668056399\)。

时间复杂度为:\(O(N^2MT\log V)\),这里 \(N\) 表示数字位数,\(V\) 表示二分值域,\(M\) 表示每次枚举填的数的个数,可看作 \(10\)。

\(\texttt{Code:}\)

#include <vector>
#include <cstring>
#include <iostream>

using namespace std;
typedef long long ll;

const int N = 20;

int T;
int x;
ll f[N][N][2];
vector<int> num;

ll dfs(int pos, int cnt, bool flag, bool limit) {
    if(pos < 0) return flag;
    if(!limit && f[pos][cnt][flag] != -1) return f[pos][cnt][flag];
    int mx = (limit ? num[pos] : 9);
    ll res = 0;
    for(int i = 0; i <= mx; i++) {
        int ncnt;
        if(i == 6) ncnt = cnt + 1;
        else ncnt = 0;
        res += dfs(pos - 1, ncnt, flag || (ncnt >= 3), limit && (i == num[pos]));
    }
    if(!limit) f[pos][cnt][flag] = res;
    return res;
}

ll calc(ll x) {
    num.clear();
    ll tmp = x;
    while(tmp) {
        num.push_back(tmp % 10);
        tmp /= 10;
    }
    return dfs(num.size() - 1, 0, 0, 1);
}

void solve() {
    scanf("%d", &x);
    ll l = 1, r = 5e18;
    while(l < r) {
        ll mid = l + r >> 1;
        if(calc(mid) >= x) r = mid;
        else l = mid + 1;
    }
    printf("%lld\n", l);
}

int main() {
    scanf("%d", &T);
    memset(f, -1, sizeof f);
    while(T--) {
        solve();
    }
    return 0;
}

标签:P10958,num,int,ll,pos,启示录,flag,解题,limit
From: https://www.cnblogs.com/Brilliant11001/p/18391140

相关文章

  • 解题招商蛇口上半年:稳中求进,坚持高质量发展
    来源:中国网近年来,房地产市场维持震荡格局,市场信心不足、销售承压、融资受阻等多重压力叠加下,行业洗牌速度进一步加快。在此背景下,招商蛇口等龙头房企依然保持财务状况安全、稳健,持续“稳中有进”,坚持高质量发展。8月30日晚,招商蛇口(001979.SZ)发布半年度业绩报告。报告期内,......
  • 信奥赛一本通陈老师解题 1123:图像相似度
    ​【题目描述】给出两幅相同大小的黑白图像(用0-1矩阵)表示,求它们的相似度。说明:若两幅图像在相同位置上的像素点颜色相同,则称它们在该位置具有相同的像素点。两幅图像的相似度定义为相同像素点数占总像素点数的百分比。【输入】第一行包含两个整数m和n,表示图像的行数和列数,......
  • 信奥赛一本通陈老师解题 1128:图像模糊处理
    ​ 【题目描述】给定n行m列的图像各像素点的灰度值,要求用如下方法对其进行模糊化处理:1.四周最外侧的像素点灰度值不变;2.中间各像素点新灰度值为该像素点及其上下左右相邻四个像素点原灰度值的平均(舍入到最接近的整数)。【输入】第一行包含两个整数n和m,表示图像包含像素......
  • 信奥一本通题南沙陈老师解题 1058:求一元二次方程
     【题目描述】【输入】输入一行,包含三个浮点数a,b,ca,b,c(它们之间以一个空格分开),分别表示方程ax2+bx+c=0ax2+bx+c=0的系数。【输出】输出一行,表示方程的解。若两个实根相等,则输出形式为:“x1=x2=...x1=x2=...”;若两个实根不等,在满足根小者在前的原则,则输出形式......
  • P10975 Mondriaan's Dream 解题报告
    题目传送门题目大意给定一个\(N\timesM\)的网格,求用\(1\times2\)和\(2\times1\)的长方形去铺满它有多少种方案。数据范围:\(N,M\le11\)。思路:考虑怎么放才能刚好填满网格。可以想到,如果先放横着的,再放竖着的,那么当我们将横着的都放完后,若竖着的恰好能刚好嵌进去,说......
  • 网络安全ctf比赛/学习资源整理,解题工具、比赛时间、解题思路、实战靶场、学习路线,推荐
    前言对于想学习或者参加CTF比赛的朋友来说,CTF工具、练习靶场必不可少,今天给大家分享自己收藏的CTF资源,希望能对各位有所帮助。CTF在线工具首先给大家推荐我自己常用的3个CTF在线工具网站,内容齐全,收藏备用。1、CTF在线工具箱:http://ctf.ssleye.com/包含CTF比赛中常用的......
  • AT_tdpc_number 数 解题报告
    题目大意求\([1,N]\)中有多少个数在十进制表示下数码和是\(D\)的倍数。数据范围:\(1\leN\le10^{10000},1\leD\le100\)。思路很明显的数位dp。这里采用了记忆化搜索来实现数位dp。记忆化搜索实现比较板子,不光写起来比较简单,而且容易扩展,所以建议大家都学习一下。......
  • 南沙区信奥赛CSP-J/S 陈老师解题:1350:【例4-11】最短网络(agrinet)
    ​ 【题目描述】农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场。你将得到一......
  • PMP考前必看!PMP解题思路分享
    俗话说“临阵磨枪,不快也光”,PMP考试前看完这几点,助你顺利上岸~1、相关方之间的冲突在执行相关方分析时,项目经理识别出两个关键干系人之间的负面关系。其中一个正在为项目提供资金,另一个是客户。项目经理应该如何处理?答:在平等基础上对待所有相关方并进行沟通,通过深入沟通......
  • 全网最易懂的解题——C语言“打印一个数的每一位(递归)”
    很简单吧递归我们做了很多题,逆序打印数字和逆序打印数组我们也做过代码就直接附上了voidmy_print(intnum){ if(num<10)//说明只有一位数字 { printf("%d",num); } else { my_print(num/10); printf("%d",num%10); }}//打印数字的每一位intmain(......