首页 > 其他分享 >[题解]P4052 [JSOI2007] 文本生成器

[题解]P4052 [JSOI2007] 文本生成器

时间:2024-08-20 13:16:46浏览次数:16  
标签:主串 JSOI2007 int 题解 生成器 模式 fail fl 节点

P4052 [JSOI2007] 文本生成器

正难则反,我们发现用总字符串个数\(26^m\),减去不可读的字符串个数,就是答案。

要使一个字符串不可读,就不能让任何模式串在其中出现。如果某个主串的第\(i\)位与自动机的节点\(j\)相匹配,那么如果状态\(j\)包含模式串(即有一个前缀是一个模式串),那么不管主串第\(i+1\)位后是什么,一定是不可读的,故此时“主串第\(i\)个字符,对应节点\(j\)”的答案是\(0\)。

再考虑\(j\)不包含任何模式串的情况,显然我们就可以把“主串第\(i-1\)个字符,对应节点\(fa[j]\)”的答案,转移到“主串第\(i\)个字符,对应节点\(j\)”上去。
其中\(fa[j]\)表示在Trie上能通过一条有向边到达\(j\)的节点,可能有多个。

因此我们用\(f[i][j]\)表示主串第\(i\)个字符,对应节点\(j\)的答案,可以得到转移:

f[0][0]=1;
for(int i=1;i<=m;i++)//枚举长度
	for(int j=0;j<=cnt;j++)//枚举所有Trie节点
		for(int c=0;c<26;c++)
			if(!fl[tr[j][c]])//如果tr[j][c]不包含模式串
				f[i][tr[j][c]]+=f[i-1][j];//j转移到tr[j][c]

最后就是如何计算\(fl\)数组,即判断某个节点是否包含模式串。这个显然能在get_fail()中一并处理出来。如果\(u\)是模式串结尾,或者\(fl[fail[u]]=1\),那么\(fl[u]=1\)。

时间复杂度是\(O(m\times \sum|s|\times |\Sigma|)\),其中建自动机是\(O(\sum|s|\times |\Sigma|)\)。

别忘了取模~

点击查看代码
#include<bits/stdc++.h>
#define mod 10007
#define N 6010//节点数(模式串总长)
#define M 110//单个模式串长度
#define C 26//字符集大小
using namespace std;
int n,m,tr[N][C],fail[N],cnt;
int q[N],head,tail,f[M][N],fa[N];
bool fl[N];
string s;
void ins(string s){
	int p=0;
	for(char i:s){
		int c=i-'A';
		if(!tr[p][c]) tr[p][c]=++cnt,fa[cnt]=p;
		p=tr[p][c];
	}
	fl[p]=1;
}
void get_fail(){
	head=0,tail=-1;
	for(int i=0;i<26;i++) if(tr[0][i]) q[++tail]=tr[0][i];
	while(head<=tail){
		int u=q[head++];
		for(int i=0;i<26;i++){
			if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q[++tail]=tr[u][i],
				fl[tr[u][i]]|=fl[fail[tr[u][i]]];
			else tr[u][i]=tr[fail[u]][i];
		}
	}
}
int qpow(int a,int b){
	int fac=1;
	while(b){
		if(b&1) fac=fac*a%mod;
		a=a*a%mod,b>>=1;
	}
	return fac;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>s;
		ins(s);
	}
	get_fail();
	int ans=0;
	f[0][0]=1;
	for(int i=1;i<=m;i++)
		for(int j=0;j<=cnt;j++)
			for(int c=0;c<26;c++)
				if(!fl[tr[j][c]])
					f[i][tr[j][c]]=(f[i][tr[j][c]]+f[i-1][j])%mod;
	for(int i=0;i<=cnt;i++) ans=(ans+f[m][i])%mod;
	ans=(qpow(26,m)-ans+mod)%mod;
	cout<<ans<<"\n";
	return 0;
}

标签:主串,JSOI2007,int,题解,生成器,模式,fail,fl,节点
From: https://www.cnblogs.com/Sinktank/p/18367816

相关文章

  • 关系代数、函数依赖、Armstrong公理及软考试题解析
    注:本文面向于软考高级—系统架构设计师,具体来说是数据库部分,知识点偏零碎化。想要系统学习数据库原理的,可考虑去看《数据库原理》,清华大学出版社或其他出版社皆可。概述概念关系,就是二维表。特性:列不可分性:关系中每一列都是不可再分的属性,即不能出现如下复合属性行列无序性:......
  • P1543 [POI2004] SZP 题解
    P1543[POI2004]SZP题解传送门。题目简述有\(n\)个人,每个人都会监视另一个人,要求选出尽可能多的同学,使得选出的每一名同学都必定会被监视到。且选出的同学不可再监视其他人。思路简述因为任意一个人只能被另一个人管,那么就想到,如果没人管的同学就不能被选(不被监视)。若某......
  • 题解:[TJOI2018] 游园会
    所谓dp套dp,实际上就是在说求解一个dp的过程中,我们用另一个dp求解出他应该从某个状态转移到另一个状态。考虑一下这道题,首先求LCS的dp如下:\[dp_{i,j}=\max\{dp_{i-1,j},dp_{i,j-1},dp_{i-1,j-1}+[s_i==t_j]\}\]显然,当\(i\)固定的时候,\(dp_{i,j}\)是单调不降的,且相邻两......
  • 【LGR-196-Div.4】洛谷入门赛 #26 题A - H 详细题解--优化思路简洁代码(C++,Python语
    前言:    觉得这个比赛很有意思的,都是暴力题,涉及一些细节,难度比较适合刚学编程语言的,可以很好的锻炼基础还有手速,最后两题也是比较有意思,之后也准备更新atc的比赛题解和洛谷的一些高质量比赛题解(算法网瘾就是想参加各种比赛)   如果觉得有帮助,或者觉得我写的好,......
  • [NOI]2024 登山 题解
    好像在洛谷题解区里还没人和我做法一样,,?考场做法,只用到了倍增和线段树,感觉挺好写。考场上从开题到过题只用了2h。最底下有省流版(?)。以下是我考场里比较详细的思路,所以比较长。先考虑如何\(O(n^2)\)做,然后再想优化。容易先想到一个状态数是\(O(n^2)\)的DP,即记录起点,并将向......
  • AGC002 题解
    目录A-RangeProductB-BoxandBallC-KnotPuzzleA-RangeProduct分情况讨论:\(a\le0\leb\)时,乘积一定为\(0\);否则:\(0<a\leb\)时,乘积一定为正;否则,负数的个数有\(b-a+1\)个,判断这个数是否为奇数,若是,乘积为负,否则为正。#include<bits/stdc++.h......
  • P10423题解
    P10423[蓝桥杯2024省B]填空问题先贴上答案#include<iostream>usingnamespacestd;intmain(){stringans[]={"1204","1100325199.77",};charT;cin>>T;cout<<ans[T-'A']......
  • P10155题解
    1题意给定一个排列ppp,每次可以选择一个数pi......
  • AT_abc027_b题解
    说明需要掌握贪心算法。这么简单为什么是黄题啊?题意给定一个长度为的非负整数序列,你可以进行若干次操作,每次操作都可以选择一个长度为的子串,花费的代价,将其中的每个数都变成该子串的平均值,现在你必须将每个数都变成相同的,你必须同时保证每个数为非负整数。分析先算......
  • 题解:「ROI 2017 Day 2」存储器
    题目信息题目链接LuoguP10653、LOJ2770题目描述给定一个字符串\(S\),设其长度为\(n\),每个字符要么是+要么是-。定义一个片段为\(S\)的一个子串\(S[l,r]\)满足下面三个条件:\(l=1\)或者\(S_{l-1}\neS_l\)。\(r=n\)或者\(S_{r+1}\neS_r\)。\(S_l=S_{l+1}=......