点此看题面

大致题意: 给你\(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. HttpClient之用CloseableHttpClient发送post请求

    使用HttpClient发送请求的一般步骤(1) 创建HttpClient对象.(2)创建请求方法的实例,并指定请求URL.如果需要发送GET请求,创建HttpGet对象:如果需要发送POST请求,创 ...

  2. WPF 精修篇 属性触发器

    原文:WPF 精修篇 属性触发器 属性触发器是通过  某个条件触发改变属性 通过无代码实现功能 <Style TargetType="{x:Type Label}"> ...

  3. Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) C. Messy 构造

    C. Messy You are fed up with your messy room, so you decided to clean it up. Your room is a bracket ...

  4. DirectShow 进行视频预览和录制

    这一篇讲怎么采集摄像头图像并预览,以及录制视频到本地. 程序实现流程 这里通过使用 CaptureGraphBuilder 来简化 Graph 的创建流程. 具体流程如下: 初始化 COM 库 创建各 ...

  5. csrf攻击与csrf防御

    CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站 ...

  6. Spring的增强模式

    一.前置增强 1.IdoSomeService 2.IdoSomeServiceImpl类实现IdoSomeService接口 3.MyBeforeAdvice 实现前置增强方法 4.applicat ...

  7. 创建workbook及相关操作

    通过openpyxl模块创建workbook时,无需本地事先创建好excel,它会直接创建一个新的excel文件 创建workbook时,会至少包含一个worksheet 注意:openpyxl模块只 ...

  8. vue 开发常见问题解决大全

    vue添加favicon.ico,包含开发环境和生产环境显示. 1.把图标放在下项目的根目录.. 2.修改build文件夹下面的webpack.dev.conf.js(开发环境) 和webpack.p ...

  9. 跟着高淇学Python——第一到第三章总结

    2019/10/26 第一章:Python介绍 Python是一种解释型,面向对象的语言.特点是: 可读性强 简洁,简洁 面向对象 免费开源 可移植性和跨平台性 丰富的库 可扩展性 应用范围:1.人工 ...

  10. MapReduce Shuffle 和 Spark Shuffle 原理概述

    Shuffle简介 Shuffle的本意是洗牌.混洗的意思,把一组有规则的数据尽量打乱成无规则的数据.而在MapReduce中,Shuffle更像是洗牌的逆过程,指的是将map端的无规则输出按指定的规 ...