咕咕(数位dp+AC自动机)
咕咕(数位dp+AC自动机)
若一个字符串的字符集合是0~m-1,那么称它为m进制字符串。给出n个m进制字符串\(s_i\),每个字符串的权值为\(v_i\)。对于另一个m进制字符串\(S\),设\(s_i\)在S中的出现次数是\(cnt_i\),那么\(s_i\)对\(S\)的价值的贡献就是\(v_i*cnt_i\)。因此,\(V_S=\Sigma_{i=1}^kcnt_i\times v_i\)。求在区间\([l, r]\)中,有多少字符串的价值不超过k。\(\Sigma_{i=1}^n|s_i|<=200\),\(|S|<=200\)。
这道题一看就是个数位dp。可是怎么dp呢?通常,数位dp的状态是\(dp[i][j]..[0/1]\),i表示dp到第几位,j及之后的维度表示状态的一些特征,1或0表示状态是否触顶。但是这道题,需要能从状态中判断出某个模式串是否在当前位上结束,这样才能转移。因此,没法用普通的数位dp方法解决这道题。
再来看看,如果\(l=r=S\)怎么做。我们发现,这就是上篇博客讲的多模式串匹配问题。一个模式串每匹配一次,答案就加上权值\(v_i\)。因此,可以用AC自动机来解决\(l=r\)的问题。
那么这道题怎么办呢?聪明的读者(哦不,上帝,我要用靴子狠狠地踢自己的屁股!)可能已经猜到了解法就是在AC自动机上数位dp。对于所有\(s_i\),把它们建成一个AC自动机。用\(dp[i][j][v][0/1]\),表示dp到原串的第i位,AC自动机上的结点为j,当前权值为v,触顶/不触顶时,有多少个数字是符合条件的。这样就能愉快的转移辣!
注意,\(s_i\)是可能有前导零的,但是\([l,r]\)中的前导零不能算。因此设置初始条件的时候一定要小心。
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const LL maxl=205, maxm=22, maxnode=205, mod=1e9+7, maxk=505;
LL n, m, k, nl, nr, l[maxl], r[maxl];
LL cnode, son[maxnode][maxm], p[maxnode], fail[maxnode];
void ins(LL n){
LL now=0, t;
for (LL i=0; i<n; ++i){
scanf("%lld", &t);
if (!son[now][t]) son[now][t]=++cnode;
now=son[now][t];
}
scanf("%lld", &t); p[now]+=t;
}
LL q[maxnode], hd, tl;
void build(){
hd=tl=0; LL now;
for (LL i=0; i<m; ++i)
if (son[0][i]) q[tl++]=son[0][i];
while (hd<tl){
now=q[hd++];
p[now]+=p[fail[now]];
for (LL i=0; i<m; ++i)
if (son[now][i])
fail[son[now][i]]=son[fail[now]][i], q[tl++]=son[now][i];
else son[now][i]=son[fail[now]][i];
}
}
void up(int &x, LL v){ LL t=x+v; t%=mod; x=t; }
void up(LL &x, LL v){ x+=v; x%=mod; }
int dp[maxl][maxnode][maxk][2];
LL solve(LL *a, LL n){
if (!n) return 0;
memset(dp, 0, sizeof(dp));
//下面要设置dp的初始条件
for (LL i=1; i<a[0]; ++i) //初始条件:第一位
if (p[son[0][i]]<=k) up(dp[0][son[0][i]][p[son[0][i]]][0], 1);
if (p[son[0][a[0]]]<=k) up(dp[0][son[0][a[0]]][p[son[0][a[0]]]][1], 1);
for (LL i=1; i<n; ++i) //枚举开头位(避免把原串的前导零计算进去)
for (LL j=1; j<m; ++j)
if (p[son[0][j]]<=k) up(dp[i][son[0][j]][p[son[0][j]]][0], 1);
for (LL i=0; i<n-1; ++i)
for (LL j=0; j<=cnode; ++j)
for (LL t=0; t<=k; ++t) //权值和
if (dp[i][j][t][0]||dp[i][j][t][1]) //加速
for (LL q=0; q<m; ++q){ //枚举下一位数字
LL s=son[j][q];
if (t+p[s]>k) continue;
up(dp[i+1][s][t+p[s]][0], dp[i][j][t][0]);
if (q<a[i+1]) up(dp[i+1][s][t+p[s]][0], dp[i][j][t][1]);
if (q==a[i+1]) up(dp[i+1][s][t+p[s]][1], dp[i][j][t][1]);
}
LL ans=0;
for (LL j=0; j<=cnode; ++j)
for (LL t=0; t<=k; ++t)
up(ans, dp[n-1][j][t][0]+dp[n-1][j][t][1]);
return ans;
}
int main(){
scanf("%lld%lld%lld", &n, &m, &k); //m进制,权值限制为k
scanf("%lld", &nl);
for (LL i=0; i<nl; ++i) scanf("%lld", &l[i]); --l[nl-1];
for (LL i=nl-1; i>=0; --i)
if (l[i]<0) l[i]+=m, --l[i-1]; else break;
if (!l[0]){ for (LL i=0; i<nl-2; ++i) l[i]=l[i+1]; --nl; }
scanf("%lld", &nr); LL t;
for (LL i=0; i<nr; ++i) scanf("%lld", &r[i]);
for (LL i=0; i<n; ++i) scanf("%lld", &t), ins(t); //根据n个模式串建立ac自动机
build();
printf("%lld\n", (solve(r, nr)-solve(l, nl)+mod)%mod);
return 0;
}
咕咕(数位dp+AC自动机)的更多相关文章
- 2019.02.15 codechef Favourite Numbers(二分+数位dp+ac自动机)
传送门 题意: 给444个整数L,R,K,nL,R,K,nL,R,K,n,和nnn个数字串,L,R,K,数字串大小≤1e18,n≤65L,R,K,数字串大小\le1e18,n\le65L,R,K,数字 ...
- [Sdoi2014]数数[数位dp+AC自动机]
3530: [Sdoi2014]数数 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 834 Solved: 434[Submit][Status][ ...
- CF 434C Tachibana Kanade's Tofu[数位dp+AC自动机]
Solution //本代码压掉后两维 #include<cstdio> #define max(a,b) (a<b?b:a) using namespace std; inline ...
- 洛谷$P4045\ [JSOI2009]$密码 $dp$+$AC$自动机
正解:$dp$+$AC$自动机+搜索 解题报告: 传送门$QwQ$ 首先显然先建个$AC$自动机,然后考虑设$f_{i,j,k}$表示长度为$i$,现在在$AC$自动机的第$j$个位置,已经表示出来的 ...
- 【hdu3247-Resource Archiver】位压DP+AC自动机+SPFA
题意:给定n个文本串,m个病毒串,文本串重叠部分可以合并,但合并后不能含有病毒串,问所有文本串合并后最短多长. (2 <= n <= 10, 1 <= m <= 1000) 题 ...
- 【HDU3247】 Resource Archiver(DP+AC自动机+最短路)
Resource Archiver Time Limit: 10000MS Memory Limit: 100000KB 64bit IO Format: %I64d & %I64u ...
- POJ 3691 DNA repair (DP+AC自动机)
DNA repair Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4815 Accepted: 2237 Descri ...
- BZOJ 1559 JSOI2009 密码 状压dp+AC自动机+搜索
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1559 分析: 这个题意真的是很**啊!!!直接说每一个字符串至少出现一次不就好了吗... ...
- poj3691 DNA repair[DP+AC自动机]
$给定 n 个模式串,和一个长度为 m 的原串 s,求至少修改原串中的几个字符可以使得原串中不包含任一个模式串.模式串总长度 ≤ 1000,m ≤ 1000.$ 先建出模式串的AC自动机,然后考虑怎么 ...
随机推荐
- NHibernate使用总结(2)
首先,映射文件的名称一定要是XXX.hbm.xml且生成方式一定要是嵌入的资源+不复制. hibernate.cfg.xml这个文件要放在根目录下,且生成方式必须是内容+始终复制. private v ...
- 机器学习:数据归一化(Scaler)
数据归一化(Feature Scaling) 一.为什么要进行数据归一化 原则:样本的所有特征,在特征空间中,对样本的距离产生的影响是同级的: 问题:特征数字化后,由于取值大小不同,造成特征空间中样本 ...
- [转]RegExp 构造函数创建了一个正则表达式对象,用于将文本与一个模式匹配
本文转自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp RegExp ...
- Microsoft Sync Framework下的快速开发同步程序
Microsoft Sync Frameworks简称MSF,是一个综合的同步平台,MSF支持应用程序,服务,设备的在线以及离线同步.MSF主要有以下几个部件组成: * Sync Servic ...
- javascript——对象的概念——函数 2 (内建函数与类型转换)
javascript 有许多内建函数,用于各种操作,以下为常用的内建方法. 1.parseInt(object,int):将输入的 int 进制的值 object 转换为 10 进制的数值: obje ...
- 12-19Windows窗体应用程序之记事本(2)
之前记事本的功能实现了“文件”和“编辑”中的功能操作,现在再继续下面的功能介绍: 3) <1>字体设置 [查看代码] [效果图] <2>字体颜色的设置 [查看代码] [效果图] ...
- leetcode377
public class Solution { private int[] dp; public int CombinationSum4(int[] nums, int target) { dp = ...
- 环境变量,include搜索路径,lib库搜索路径
环境变量 系统环境变量 我们知道,我们经常要设置一些环境变量,系统环境变量我们非常容易理解.其实我们在windows中经常容易接触.其实环境变量是一个非常广泛的一个概念,它与web应用程序中的web. ...
- 异常 android.content.res.Resources$NotFoundException: String resource ID #0x61
09-09 16:08:41.554: E/Weaver(13140):09-09 16:08:41.554: E/Weaver(13140): android.content.res.Resourc ...
- [P3812][模板]线性基
解题关键:求异或最大值.线性基模板题. 极大线性无关组的概念. 异或的值域相同. #include<cstdio> #include<cstring> #include< ...