[BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】
题目链接: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步) ...
随机推荐
- linux服务器上
命令行>mysql -uwin -pwin2009进入mysql command状态>use mindo时入mindo数据库>source 500sql.txt执行sql
- MVC架构杂谈
来源:伯乐在线专栏作者 - 林欣达 链接:http://ios.jobbole.com/86895/ 点击 → 了解如何加入专栏作者 前言 MVC是软件工程中的一种软件架构模式,它把软件系统分为三个基 ...
- 学习笔记_Java get和post区别(转载_GET一般用于获取/查询资源信息,而POST一般用于更新资源信息)
转载自:[hyddd(http://www.cnblogs.com/hyddd/)] 总结一下, Get是向服务器发索取数据的一种请求 而Post是向服务器提交数据的一种请求,在F ...
- JQuery的几种页面加载完执行三种方式
jquery加载页面的方法(页面加载完成就执行) 1. $(function(){ $("#a").click(function(){ //adding your code h ...
- iOS 设置图片imageView圆角——对图片进行裁剪
以前设置图片圆角总是把imageView设置成圆形,然后设置maskToBounds为YES,其实这样处理很消耗性能,图片多了之后比较卡,最好将图片进行裁剪后显示:这里有个分类可以用: UIImage ...
- java新手笔记5 类
1.进制转换 /* 企业发放的奖金根据利润提成. 利润(I)低于或等于10万元时,奖金可提10%: 利润高于10万元,低于20万元时, 低于10万元的部分按10%提成,高于10万元的部分,可提成7.5 ...
- java ,js获取web工程路径
一.java获取web工程路径 1),在servlet可以用一下方法取得: request.getRealPath(“/”) 例如:filepach = request.getRealPath(“/” ...
- 【制作镜像】BCEC制作镜像
如要制作的新镜像已存在标准版本镜像,即linux发行版本相同(此处指CentOS6.5 64位),可利用BCEC制作. 在BCEC创建centos6.5系统的可联外网的虚机,ssh到此虚机,用yum方 ...
- Codevs 1183 泥泞的道路
1183 泥泞的道路 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description CS有n个小区,并且任意小区之间都有两条单向道路 ...
- [工具]toolbox_graph基本操作
toolbox_graph提供了对3D模型的一些操作.MATLAB代码源自:http://www.mathworks.com/matlabcentral/fileexchange/5355-toolb ...