首页 > 其他分享 >P3311 [SDOI2014] 数数

P3311 [SDOI2014] 数数

时间:2024-09-25 17:04:09浏览次数:9  
标签:10 数数 ch ver int P3311 st SDOI2014 limit

参考题解做法。

题目

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;
}

标签:10,数数,ch,ver,int,P3311,st,SDOI2014,limit
From: https://www.cnblogs.com/Yuan-Jiawei/p/18431700

相关文章

  • 2024-09-18:用go语言,给定一个从 0 开始的长度为 n 的正整数数组 nums 和一个二维操作数
    2024-09-18:用go语言,给定一个从0开始的长度为n的正整数数组nums和一个二维操作数组queries,每个操作由一个下标值indexi和一个数值ki组成。开始时,数组中的所有元素都是未标记的。依次执行m次操作,每次操作的过程如下:1.如果下标indexi对应的元素还未标记,则标记这个元素......
  • 2024-09-14:用go语言,给定一个正整数数组 nums,定义一个加密函数 encrypt(x),其将一个整数
    2024-09-14:用go语言,给定一个正整数数组nums,定义一个加密函数encrypt(x),其将一个整数x的每一位数字都替换为x中的最大数字,然后返回加密后的数字。例如,encrypt(523)会返回555,encrypt(213)会返回333。现在需要计算数组中所有元素加密后的和,然后返回这个和。输入:nums=[10,2......
  • 2024-09-18:用go语言,给定一个从 0 开始的长度为 n 的正整数数组 nums 和一个二维操作数
    2024-09-18:用go语言,给定一个从0开始的长度为n的正整数数组nums和一个二维操作数组queries,每个操作由一个下标值indexi和一个数值ki组成。开始时,数组中的所有元素都是未标记的。依次执行m次操作,每次操作的过程如下:1.如果下标indexi对应的元素还未标记,则标记这个元素......
  • MATLAB系列06:复数数据、字符数据和附加画图类
    MATLAB系列06:复数数据、字符数据和附加画图类6.复数数据、字符数据和附加画图类6.1复数数据6.1.1复变量(complexvariables)6.1.2带有关系运算符的复数的应用6.1.3复函数(complexfunction)6.1.4复数数据的作图6.2字符串函数6.2.1字符转换函数6.2.2创建二维字符......
  • ZR24NOIP1B. 数数
    ZR24NOIP1B.数数给你一个长度为\(n\le1600\)的二进制数,其中某些位未知,是?。问?的所有取值得到的\(x\),\([0,x-1]\)中不含长度为\(k\le20\)的回文串的数字(含前导\(0\))的个数的和。首先显然是数位DP。考虑从高位枚举到低位,假设没有?,状态记位数\((1600)\)和是否顶......
  • 2024-09-14:用go语言,给定一个正整数数组 nums,定义一个加密函数 encrypt(x),其将一个整数
    2024-09-14:用go语言,给定一个正整数数组nums,定义一个加密函数encrypt(x),其将一个整数x的每一位数字都替换为x中的最大数字,然后返回加密后的数字。例如,encrypt(523)会返回555,encrypt(213)会返回333。现在需要计算数组中所有元素加密后的和,然后返回这个和。输入:nums=[10,2......
  • OpenAI使用AI编程给出了数数问题的解决方案 —— 如何解决ChatGPT不会数数的问题
    总所周知的一个问题,那就是ChatGPT不会数数,不过今天突然发现OpenAI给出了一个神奇的解决方法,那就是AI编程。问题案例如下:Thetextprovidedwillbeanalyzedtocalculatethewordcount.text="""Therehasbeenrapidlygrowinginterestinmeta-learningasamet......
  • P3312 [SDOI2014] 数表
    [SDOI2014]数表题目描述有一张\(n\timesm\)的数表,其第\(i\)行第\(j\)列(\(1\lei\len\),\(1\lej\lem\))的数值为能同时整除\(i\)和\(j\)的所有自然数之和。给定\(a\),计算数表中不大于\(a\)的数之和。输入格式输入包含多组数据。输入的第一行一个整数\(Q\)表......
  • 2024-09-11:用go语言,给定一个从0开始的整数数组nums和一个正奇数整数k, 要求在nums数组
    2024-09-11:用go语言,给定一个从0开始的整数数组nums和一个正奇数整数k,要求在nums数组中选择k个不重叠的子数组,使得这些子数组的能量值之和最大。子数组的能量值是通过一定规则计算得到的,具体规则是对于某个子数组,将其每个元素乘以一个特定系数,并将这些结果相加,系数随着元素在子数组......
  • 几道数数
    abc240g只考虑\(0\leqX,Y,Z\)的情况,显然小于0时的路径可以与大于0的一一对应。考虑我们三个方向的增量分别需要\(X,Y,Z\),剩下的步数显然是通过走一步该方向又走回来这样子消耗。记\(m=(N-X-Y-Z)/2\)。如果\(N-X-Y-Z\)是奇数或者\(N<X+Y......