点此看题面

大致题意: 给你\(n\)个字符串,问你有多少个长度为\(L\)的字符串,使得这些字符串都是它的子串。若个数不大于\(42\),按字典序输出所有方案。

状压

显然,由于\(n\)很小,我们可以把每个字符串是否出现过状压起来。

这样就可以起到极大的优化作用。

我们可以对每个节点开一个变量\(Ex\)记录一下该节点存在哪些字符串,转移起来就很方便了。

\(AC\)自动机上\(DP\)

由于和子串有关,这题可以看做是一个多模匹配问题。

所以,我们考虑建出\(AC\)自动机。

然后,我们就可以\(DP\)了。

设\(f_{p,i,j}\)表示现在是第\(p\)个字符,走到\(AC\)自动机上第\(i\)个节点,每个字符串出现状态状压起来为\(j\)的方案数。

转移应该是比较套路的,每次把信息向子节点转移,同时\(j\)要或上子节点的\(Ex\)值。

最后的答案就是\(\sum f_{L,i,2^n-1}\)。

具体方案

我们对每个状态开个\(vector\)记录一下能从哪些非\(0\)状态转移过来,然后倒着\(dfs\)一遍就可以求出所有方案了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 10
#define M 25
#define LL long long
using namespace std;
int n,m;
class AcAutomation//AC自动机
{
private:
#define pb push_back
int rt,Nt;short q[N*M+5];long long f[M+5][N*N+5][1<<N];
short cnt;string res[45];struct Trie {int Ex,F,S[30];}O[N*N+5];
struct Status
{
short y,z,v;I Status(CI b=0,CI c=0,CI k=0):y(b),z(c),v(k){}
};vector<Status> g[M+5][N*N+5][1<<N];
public:
I AcAutomation() {rt=Nt=1;}
I void Insert(CI p,Con string& s)//插入字符串
{
RI i,l=s.length(),x=rt,k;for(i=0;i^l;++i)
!O[x].S[k=s[i]&31]&&(O[x].S[k]=++Nt),x=O[x].S[k];
O[x].Ex|=1<<p-1;
}
I void Build()//建AC自动机
{
RI i,j,k,p,H=1,T=0;for(i=1;i<=26;++i)
{
if(!(p=O[rt].S[i])) {O[rt].S[i]=rt;continue;}
O[q[++T]=p].F=rt,O[p].Ex|=O[O[p].F].Ex;
}
W(H<=T) for(k=q[H++],i=1;i<=26;++i)
{
if(!(p=O[k].S[i])) {O[k].S[i]=O[O[k].F].S[i];continue;}
O[q[++T]=p].F=O[O[k].F].S[i],O[p].Ex|=O[O[p].F].Ex;
}
}
I void Travel(CI x,CI y,CI z,Con string& s)//倒序找出所有方案
{
if(!x) return (void)(res[++cnt]=s);vector<Status>::iterator it;
for(it=g[x][y][z].begin();it!=g[x][y][z].end();++it) Travel(x-1,it->y,it->z,(char)(96+it->v)+s);
}
I void Solve()//DP求解
{
RI p,i,j,k,t=1<<n;long long ans=0;for(f[0][1][0]=1,p=1;p<=m;++p) for(i=1;i<=Nt;++i)//DP转移求解第一个询问
for(j=0;j^t;++j) for(k=1;k<=26;++k) f[p][O[i].S[k]][j|O[O[i].S[k]].Ex]+=f[p-1][i][j];
for(i=1;i<=Nt;++i) ans+=f[m][i][t-1];if(printf("%lld\n",ans),ans>42) return;//统计答案并输出
for(p=1;p<=m;++p) for(i=1;i<=Nt;++i) for(j=0;j^t;++j)//DP转移求解第二个询问
for(k=1;k<=26;++k) f[p-1][i][j]&&(g[p][O[i].S[k]][j|O[O[i].S[k]].Ex].pb(Status(i,j,k)),0);
for(i=1;i<=Nt;++i) f[m][i][t-1]&&(Travel(m,i,t-1,""),0);//找方案
for(sort(res+1,res+ans+1),i=1;i<=ans;++i) cout<<res[i]<<endl;//输出方案
}
}A;
int main()
{
RI i;string s;for(scanf("%d%d",&m,&n),i=1;i<=n;++i) cin>>s,A.Insert(i,s);
return A.Build(),A.Solve(),0;
}

【洛谷4045】[JSOI2009] 密码(状压+AC自动机上DP)的更多相关文章

  1. BZOJ 1559 JSOI2009 密码 状压dp+AC自动机+搜索

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1559 分析: 这个题意真的是很**啊!!!直接说每一个字符串至少出现一次不就好了吗... ...

  2. 2018.11.02 洛谷P2831 愤怒的小鸟(状压dp)

    传送门 状压一眼题. 直接f[i]f[i]f[i]表示未选择状态为iii时的最小次数. 然后考虑现在怎么转移. 显然可以直接枚举消掉某一个点或者某两个点,复杂度O(n22n)O(n^22^n)O(n2 ...

  3. 洛谷P3959 宝藏(状压dp)

    传送门 为什么感觉状压dp都好玄学……FlashHu大佬太强啦…… 设$f_{i,j}$表示当前选的点集为$i$,下一次要加入的点集为$j$时,新加入的点和原有的点之间的最小边权.具体的转移可以枚举$ ...

  4. 洛谷P2473奖励关——状压DP

    题目:https://www.luogu.org/problemnew/show/P2473 还是对DP套路不熟悉... 像这种前面影响后面,而后面不影响前面的问题就应该考虑倒序递推: 看n只有15那 ...

  5. 洛谷 P3112 后卫马克 —— 状压DP

    题目:https://www.luogu.org/problemnew/show/P3112 状压DP...转移不错. 代码如下: #include<iostream> #include& ...

  6. 【洛谷4941】War2 状压Dp

    简单的状压DP,和NOIP2017 Day2 找宝藏 代码几乎一样.(比那个稍微简单一点) f[i][j] ,i代表点的状态,j是当前选择的点,枚举上一个选到的点k 然后从f[i-(1<< ...

  7. 洛谷 3959 宝藏——枚举+状压dp

    题目:https://www.luogu.org/problemnew/show/P3959 原来写了个不枚举起点的状压dp. #include<iostream> #include< ...

  8. 洛谷$P3959\ [NOIp2017]$ 宝藏 状压$dp$

    正解:状压$dp$ 解题报告: 传送门$QwQ$ $8102$年的时候就想搞这题了,,,$9102$了$gql$终于开始做这题了$kk$ 发现有意义的状态只有当前选的点集和深度,所以设$f_{i,j} ...

  9. 洛谷 P1433 吃奶酪 状压DP

    题目描述 分析 比较简单的状压DP 我们设\(f[i][j]\)为当前的状态为\(i\)且当前所在的位置为\(j\)时走过的最小距离 因为老鼠的坐标为\((0,0)\),所以我们要预处理出\(f[1& ...

随机推荐

  1. vue-cil3 运行报错 --- warnings potentially fixable with the `--fix` option

    warnings potentially fixable with the `--fix` option. 将一下部分:"lint": "vue-cli-service ...

  2. mysql关联两张表时的编码问题

    Mysql关联两张表时,产生错误提示Illegal mix of collations 1.先用工具把数据库.两张表的编码方式改变 2.这步很重要,需要改变字段的编码方式. ALTER TABLE ` ...

  3. 记录libreoffice实现office转pdf(适用于windows、linux)

    由于目前的工作跟office打交道比较多,所以才有了此篇blog,需求是实现word转换pdf方便页面展示.之前lz采用的是jacob(仅支持windows)进行转换的,但是现在服务器改成linux显 ...

  4. Python的定时执行

    最近手把手教妹子写Python,被一篇博客误导了,这里记录一下. 妹子需要的是一个定时闹钟,到点往钉钉群里推个消息.她一顿搜索猛如虎,参照着其他人的博客,搞了一个while: target_time ...

  5. Vue实现简单的列表金额计算效果(简易购物车)

    效果图: 使用技术:v-for v-bind v-on实现简单的列表选中绑定操作 代码: <!DOCTYPE html> <html> <head> <met ...

  6. .net WebApi 批量文件进行压缩zip以二进制流传输至前端(Vue)下载

    前言:最近接了个项目,需要进行将服务端生成的文件进行打包压缩供前端下载,百度查了下资料,决定采用SharpZipLib C#开园的压缩解压库进行服务器文件压缩,在实现过程,郁闷的是前端接收下载下来的压 ...

  7. 性能篇系列—stream详解

    Stream API Java 8集合中的Stream相当于高级版的Iterator Stream API通过Lambda表达式对集合进行各种非常便利高效的聚合操作,或者大批量数据操作 Stream的 ...

  8. iOS10 新特性一

    链接:http://www.jianshu.com/p/0cc7aad638d9 1.Notification(通知) 自从Notification被引入之后,苹果就不断的更新优化,但这些更新优化只是 ...

  9. Python—基础之杂货铺

    列表.元组.字典之前的互相转换 列表与元组的转换 # 列表转换成元组:使用 tuple 函数 num_list = [3, 6, 9] num_tuple = tuple(num_list) prin ...

  10. 详解YUV数据格式

    我们在讲 FFmpeg 系列的时候,有提到 YUV 的.其中包括YUV播放器.简单的YUV格式介绍. 一.YUV简介 YUV,是一种颜色编码方法.常使用在各个影像处理元件中. YUV在对照片或影片编码 ...