题目链接:BZOJ - 3530
题目分析
明显是 AC自动机+DP,外加数位统计。
WZY 神犇出的良心省选题,然而去年我太弱..比现在还要弱得多..
其实现在做这道题,我自己也没想出完整解法..
就想出了个 O(l^3) 的做法:
完全按照数位统计的思想来,先统计长度不足 len 的数字的合法种类数,这个枚举开头,然后 AC 自动机 DP 一下,用 f[i][j] 表示到了第 i 位,在第 j 个节点上的合法数字个数。这样是 O(L^2)。
然后长度等于 n 的部分,就按照数位统计,一位位向后推,然后每次 O(L^2) DP 求,这样总的复杂度是 O(L^3)。
注意不能走包含模式串的节点,首先 Trie 中模式串的节点肯定不能走,其次,如果沿着一个节点的 Fail 链一直向上走,只要链上有一个节点是不能走的,那么这个节点也就不能走了。
所以需要从每个的节点开始,逆着 Fail 的边 DFS 一下,如果当前状态下将经过的点全都 Ban 掉。但是数据好像比较弱,不加这个也是不会出问题的。
但是这样会弄错一种情况:比如有 123, 2 这两个串,然后它就沿着 -> 1 -> 2 一直向后匹配,没有匹配成功 123 ,但是其实已经包含了 2 这个串。
这样的复杂度只有70分。
正解的复杂度是 O(L^2) 的:对于长度不足 len 的数字,还是直接求,O(L^2)。
对于长度等于 len 的数字,我们就直接用一个 O(L^2) 的 DP 求出来,我们把状态增加一维, g[i][j][k] ,前两位是第 i 位,走到第 j 个节点,k 是一个 [0/1] 变量,表示这个状态是否是沿着 n 的每一位走过来。
这样我们就知道了,如果当前状态是依照 n 的每一位走过来,那么下一步就只能转移 [0, n[i+1]] 这些数字。否则可以转移所有的数字。这样就求出了小于等于 n 的所有合法数字。
总的复杂度是 O(L^2) 。
AC自动机+DP的一般做法:f[i][j] 表示走了 i 步,走到了第 j 个节点,有时还需要加第 3 维或更多。
然后 DP 的时候就是 枚举 i ,枚举 j,枚举转移到下一步的字符。
代码
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <queue> using namespace std; const int MaxL = 1500 + 5, MaxNode = 15000 + 5, Mod = 1000000007; int len, l, m, Index, Ans;
int f[MaxL][MaxNode], g[MaxL][MaxNode][2]; char S[MaxL], Ns[MaxL]; struct Trie
{
int x, Idx;
bool Ban;
Trie *Fail, *Child[10];
} TA[MaxNode], *P = TA, *Root, *Zero; Trie* NewNode(int Num = 0)
{
++P;
P -> x = Num;
P -> Idx = ++Index;
P -> Fail = NULL;
P -> Ban = false;
memset(P -> Child, 0, sizeof(P -> Child));
return P;
} void Insert(char *S, int l)
{
int t;
Trie *Now = Root;
for (int i = 1; i <= l; ++i)
{
t = S[i] - '0';
if (Now -> Child[t] == NULL)
Now -> Child[t] = NewNode(t);
Now = Now -> Child[t];
}
Now -> Ban = true;
} struct Edge
{
int v;
Edge *Next;
} E[MaxNode], *PE = E, *Point[MaxNode]; inline void AddEdge(int x, int y)
{
++PE; PE -> v = y;
PE -> Next = Point[x]; Point[x] = PE;
} bool Visit[MaxNode]; void DFS(int x, bool f)
{
Visit[x] = true;
TA[x].Ban = (TA[x].Ban) || f;
for (Edge *j = Point[x]; j; j = j -> Next)
DFS(j -> v, TA[x].Ban);
} queue<Trie *> Q; void Build_Fail()
{
while (!Q.empty()) Q.pop();
Q.push(Root);
Trie *Now;
while (!Q.empty())
{
Now = Q.front(); Q.pop();
AddEdge(Now -> Fail -> Idx, Now -> Idx);
for (int i = 0; i <= 9; ++i)
{
if (Now -> Child[i] == NULL) Now -> Child[i] = Now -> Fail -> Child[i];
else
{
Now -> Child[i] -> Fail = Now -> Fail -> Child[i];
Q.push(Now -> Child[i]);
}
}
}
for (int i = 1; i <= Index; ++i)
if (!Visit[i]) DFS(i, TA[i].Ban);
} void Usual_Disco()
{
memset(f, 0, sizeof(f));
for (int i = 1; i <= 9; ++i)
if (Root -> Child[i] -> Ban == false)
++f[1][Root -> Child[i] -> Idx];
for (int i = 1; i < len; ++i)
for (int j = 1; j <= Index; ++j)
{
if (TA[j].Ban) continue;
Ans = (Ans + f[i][j]) % Mod;
for (int t = 0; t <= 9; ++t)
if (!TA[j].Child[t] -> Ban)
{
f[i + 1][TA[j].Child[t] -> Idx] += f[i][j];
f[i + 1][TA[j].Child[t] -> Idx] %= Mod;
}
}
memset(g, 0, sizeof(g));
for (int i = 1; i < Ns[1] - '0'; ++i)
if (Root -> Child[i] -> Ban == false)
++g[1][Root -> Child[i] -> Idx][0];
if (Root -> Child[Ns[1] - '0'] -> Ban == false)
++g[1][Root -> Child[Ns[1] - '0'] -> Idx][1];
for (int i = 1; i <= len; ++i)
for (int j = 1; j <= Index; ++j)
{
if (TA[j].Ban) continue;
if (i == len)
{
Ans = (Ans + g[i][j][0]) % Mod;
Ans = (Ans + g[i][j][1]) % Mod;
continue;
}
for (int t = 0; t <= 9; ++t)
if (!TA[j].Child[t] -> Ban)
{
g[i + 1][TA[j].Child[t] -> Idx][0] += g[i][j][0];
g[i + 1][TA[j].Child[t] -> Idx][0] %= Mod;
}
for (int t = 0; t < Ns[i + 1] - '0'; ++t)
if (!TA[j].Child[t] -> Ban)
{
g[i + 1][TA[j].Child[t] -> Idx][0] += g[i][j][1];
g[i + 1][TA[j].Child[t] -> Idx][0] %= Mod;
}
if (!TA[j].Child[Ns[i + 1] - '0'] -> Ban)
{
g[i + 1][TA[j].Child[Ns[i + 1] - '0'] -> Idx][1] += g[i][j][1];
g[i + 1][TA[j].Child[Ns[i + 1] - '0'] -> Idx][1] %= Mod;
}
}
} int main()
{
scanf("%s", Ns + 1);
len = strlen(Ns + 1);
scanf("%d", &m);
Root = NewNode();
Zero = NewNode();
Root -> Fail = Zero;
for (int i = 0; i <= 9; ++i) Zero -> Child[i] = Root;
for (int i = 1; i <= m; ++i)
{
scanf("%s", S + 1);
l = strlen(S + 1);
Insert(S, l);
}
Build_Fail();
Usual_Disco();
Ans %= Mod;
cout << Ans << endl;
return 0;
}
[BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】的更多相关文章
-
[BZOJ 1559] [JSOI2009] 密码 【AC自动机DP】
题目链接:BZOJ - 1559 题目分析 将给定的串建成AC自动机,然后在AC自动机上状压DP. 转移边就是Father -> Son 或 Now -> Fail. f[i][j][k] ...
-
【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂
[题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...
-
BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]
1212: [HNOI2004]L语言 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1367 Solved: 598[Submit][Status ...
-
BZOJ 1030: [JSOI2007]文本生成器 [AC自动机 DP]
1030: [JSOI2007]文本生成器 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3953 Solved: 1614[Submit][Stat ...
-
【BZOJ3530】数数(AC自动机,动态规划)
[BZOJ3530]数数(AC自动机,动态规划) 题面 BZOJ 题解 很套路的\(AC\)自动机+\(DP\) 首先,如果长度小于\(N\) 就不存在任何限制 直接大力\(DP\) 然后强制限制不能 ...
-
洛谷P3311 [SDOI2014]数数 AC自动机+dp
正解:AC自动机+dp 解题报告: 传送门! 首先看到多串匹配balabala显然想到建个AC自动机? 然后可以用一点儿数位dp的思想地想下(,,,其实并不算QAQ 幸运数可以分为两类:位数<n ...
-
bzoj 1030 [JSOI2007]文本生成器(AC自动机+DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1030 [题意] 给n个小串,随机构造一个长为m的大串,一个串合法当且仅当包含一个或多个 ...
-
POJ1625 Censored!(AC自动机+DP)
题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...
-
HDU2457 DNA repair(AC自动机+DP)
题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...
随机推荐
-
ATM+购物车
本次代码的实现用到了模块间的互相调用,这对于初学者而言有些难度,不过这也是我们必须要掌握的,在以后的大程序中,多个模块会让我们的代码看起来简洁明了,易排错 (本次代码只是简单的实现的基本的功能,其代码 ...
-
thinkphp3.2.x版本中图片上传缩略图的解决方案
调用方式很简单 get_sc($cover_id,[$width=180,$height=auto,$cut]) @param $cover_id 图片ID___ @param $width 宽度__ ...
-
DirectFB学习笔记四
本篇目的,实现按钮的点击事件捕获,也就是鼠标点击,如果点击在方框范围内,则响应,在方框外,则忽略. 由于鼠标移动和点击都会产生事件,因此,我们可以在鼠标移动的时候记录坐标,在点击时比较坐标是否在方框范 ...
-
Do-Now—团队冲刺博客三
Do-Now-团队 冲刺博客三 作者:仇夏 前言 不知不觉我们的项目已经做了三个多礼拜了,团队冲刺博客也写到了这第三篇,看着一个基本成型的APP安装在自己的手机上,一种喜悦感油然而生.好了,现在来看看 ...
-
[Swift]LeetCode739. 每日温度 | Daily Temperatures
Given a list of daily temperatures T, return a list such that, for each day in the input, tells you ...
-
nignx部署Vue单页面刷新路由404问题解决
官网说明: https://router.vuejs.org/zh/guide/essentials/history-mode.html#%E8%AD%A6%E5%91%8A 在linux下搭建ngi ...
-
前端CSS3笔记
第1章CSS3简介 如同人类的的进化一样,CSS3是CSS2的“进化”版本,在CSS2基础上,增强或新增了许多特性, 弥补了CSS2的众多不足之处,使得Web开发变得更为高效和便捷. 1.1 CS ...
-
使用自定义的Adapter来设置ListView的内容
这里主要是学习的Adapter的机制 MainActivity.java package com.kale.listview; import android.app.Activity; import ...
-
java之throw和throws
抛出异常有三种形式,一是throw,一个throws,还有一种系统自动抛异常.下面它们之间的异同. 一.系统自动抛异常 当程序语句出现一些逻辑错误.主义错误或类型转换错误时,系统会自动抛出异常:(举个 ...
-
Apache Tomcat 8.5 安全配置与高并发优化
通常我们在生产环境中,Tomcat的默认配置显然不能满足我们的产品需求,所以很多时候都需要对Tomcat的配置进行调优,以下综合我自己的经验来配置 Tomcat 安全与优化情况,如果你有更好的方案,请 ...