P3311 [SDOI2014] 数数

news/2024/9/25 17:03:46/文章来源:https://www.cnblogs.com/Yuan-Jiawei/p/18431700

参考题解做法。

题目

image

思路

数位 dp + AC 自动机好题。

直接往下递归,dfs(u, ver, limit, st) 表示目前在数字 \(n\) 的第 \(u\) 位进行讨论,\(ver\) 表示当前在 AC 自动机上的节点,\(limit\) 是是否步步紧逼 \(n\),只要位数不足 \(n\) 的位数或者有一位小于 \(n\) 的那一位就不叫步步紧逼,\(st\) 表示现在是否已经进入数字,因为很多数字位数不如 \(n\),就相当于在它们前面填充 \(0\)

在往下递归过程中,如果遇到边界,那么立刻返回 1,注意对 \(0\) 的特判(题目中说是 \(1\)\(n\),不是 \(0\)\(n\));可以确认这个 DP 是个 DAG,所以加上记忆化搜索,避免 TLE;getfail 时注意传递标识。

代码

#include <bits/stdc++.h>using namespace std;const int N = 1510, mod = 1e9 + 7;string s, n;
int t;
int f[N][N * 10][2][2];struct _ac {int ch[N][10], fail[N * 10], idx;bool val[N * 10];void insert(string& s) {int p = 0;for (auto x : s) {int u = x - '0';if (!ch[p][u]) ch[p][u] = ++idx;p = ch[p][u];}val[p] = 1;}void getfail() {queue<int> q;for (int i = 0; i < 10; i++) {if (ch[0][i]) {q.push(ch[0][i]);}}while (q.size()) {int t = q.front();q.pop();for (int i = 0; i < 10; i++) {if (ch[t][i]) {fail[ch[t][i]] = ch[fail[t]][i];q.push(ch[t][i]);val[ch[t][i]] |= val[fail[ch[t][i]]];}else ch[t][i] = ch[fail[t]][i];}}}
} ac;int dfs(int u, int ver, bool limit, bool st) {      // u : 数字 n 的长度, ver : 对应 ac 自动机的节点编号, limit : 是否被限制, st : 是否还未进入数字(用 0 填充)if (ac.val[ver]) return 0;                      // 如果遇到标记,立即返回if (u >= n.size()) return !st;                  // 注意对 0 的去除if (f[u][ver][limit][st] != -1) return f[u][ver][limit][st];// 记忆化搜索int up = limit ? n[u] - '0' : 9;                // 限制int ans = 0;                                    // 结果for (int i = 0; i <= up; i++) {bool nxt_limit = (limit && i == up) ? true : false;bool nxt_st = (st && i == 0) ? true : false;int  nxt_ver = (st && i == 0) ? 0 : ac.ch[ver][i];ans = (ans + dfs(u + 1, nxt_ver, nxt_limit, nxt_st)) % mod;}f[u][ver][limit][st] = ans;return ans;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);memset(f, -1, sizeof(f));cin >> n;cin >> t;while (t--) {cin >> s;ac.insert(s);}ac.getfail();int res = dfs(0, 0, true, true);cout << res << '\n';return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/803551.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验1

任务1 源代码1 #include <stdio.h> 2 int main() 3 { 4 printf("o \n"); 5 printf("<H>\n"); 6 printf("I I\n"); 7 8 return 0; 9 }

initrdinit进程

initrd的全名是 init ramdisk,是一个启动时存在于内存的文件系统。 kernal 到 initrd的流程在GRUB加载kernel时,kernel会先在内存中制造一个rootfs当做临时的空间供系统使用,接下来,kernel便会将initrd当做是一个系统,将其mount到rootfs上启动。 引入initrd的目的是为了把…

如何部署北斗定位应用,基于国产自主架构LS2K1000LA-i处理器平台

北斗卫星导航系统(以下简称北斗系统)是着眼于国内经济社会发展需要,自主建设、独立运行的卫星导航系统。经过多年发展,北斗系统已成为面向全球用户提供全天候、全天时、高精度定位、导航与授时服务的重要新型基础设施。图 1 北斗定位系统的应用优势 强可控:北斗系统是国内…

ChatGPT 向更多用户推出高级语音模式:支持 50 种语言;字节发布两款新视频生成大模型丨 RTE 开发者日报

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点…

题解:CF573D Bear and Cavalry

CF因为这是远古题目,所以根据现在的评测机速度,用 \(O(nq)\) 的做法也是可以过的。 也就是说,我们可以每次操作直接修改对应位置上的数字,然后设计一种 \(O(n)\) 的算法求解答案。 这道题类似资源分配型动态规划,所以我们可以设 \(dp_i\) 表示分配前 \(i\) 个人的答案。 直…

题解:AT_abc204_e [ABC204E] Rush Hour 2

LG变形的 dijkstra。 先思考什么情况下需要等待以及等待多长时间最优。我们把题目上的计算方法按照当前的时间 \(t\) 和通过所需的时间 \(f(t)\) 列个函数关系: \[f(t)=t+c+\lfloor \frac{d}{t+1}\rfloor \]然后用 Desmos 画个图可以得到图像(其实就是对勾函数):因为 \(c,d…

Rust字符串类型全解析

字符串是每种编程语言都绕不开的类型, 不过,在Rust中,你会看到远比其他语言更加丰富多样的字符串类型。 如下图:为什么Rust中需要这么多种表示字符串的类型呢? 初学Rust时,可能无法理解为什么要这样设计?为什么要给使用字符串带来这么多不必要的复杂性? 其实,Rust中对…

AI自动生成代码注释

在vscode 中安装 TONGYI Lingma

通过 Tampermonkey 实现学习通全自动刷课

本文介绍了如何使用 Tampermonkey 这一流行的用户脚本管理器,通过其脚本库实现学习通的全自动刷课。文章详细讲解了 Tampermonkey 的安装步骤、OCS 脚本的配置方法,以及题库的使用流程,帮助读者高效完成学习任务。在学习过程中,自动化工具能大大提升学习效率。Tampermonkey…

KBU1010-ASEMI单向整流桥KBU1010

KBU1010-ASEMI单向整流桥KBU1010编辑:ll KBU1010-ASEMI单向整流桥KBU1010 型号:KBU1010 品牌:ASEMI 封装:KBU-4 批号:2024+ 类型:单向整流桥 电流(ID):10A 电压(VF):1000V 安装方式:直插式封装 特性:大功率、整流扁桥 产品引线数量:4 产品内部芯片个数:4 产品内部…

Kubernetes中Ingress的原理和配置

Ingress的概念和作用 Ingress是Kubernetes集群中的一个对象,用于将外部流量路由到集群内部的服务。它充当了进入Kubernetes集群的API网关,负责接收外部请求,并将其转发到正确的目标服务上。 Ingress通常通过HTTP和HTTPS提供对服务的访问,并支持基于主机名、路径以及其他HTT…