首页 > 其他分享 >「刷题记录」[JSOI2007] 文本生成器

「刷题记录」[JSOI2007] 文本生成器

时间:2023-07-22 15:56:14浏览次数:55  
标签:ac ch JSOI2007 int 生成器 tr fr fail 刷题

第一道 AC 自动机 + DP 题。

题目链接:P4052 [JSOI2007] 文本生成器 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

利用容斥原理的思想,答案就是所有串的数量减去不可读的串的数量。

设 \(dp \left(i, j \right)\) 表示串长为 \(i\),在 AC 自动机上走到编号为 \(j\) 时不经过单词结尾的路径条数。

转移方程:

该节点不是单词结尾状态:dp[i][ac[j].tr[c]] += dp[i - 1][j] % mod

这类题的状态十分固定,一般为 \(dp \left (i, j \right )\),表示串长为 \(i\),状态为 \(j\) 的情况。

代码:

/*
  The code was written by yifan, and yifan is neutral!!!
 */

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 110;
const int M = 10010;
const int mod = 1e4 + 7;

int n, m, tot;
char s[N];
int dp[N][6010];
queue<int> q;

struct node {
	int fail, End;
	int tr[26];
} ac[M];

void Insert(char* s) {
	int l = strlen(s), u = 0;
	for (int i = 0; i < l; ++ i) {
		if (!ac[u].tr[s[i] - 'A']) {
			ac[u].tr[s[i] - 'A'] = ++ tot;
		}
		u = ac[u].tr[s[i] - 'A'];
	}
	ac[u].End = 1;
}

void get_fail() {
	for (int i = 0; i < 26; ++ i) {
		if (ac[0].tr[i]) {
			ac[ac[0].tr[i]].fail = 0;
			q.emplace(ac[0].tr[i]);
		}
	}
	while (!q.empty()) {
		int fr = q.front();
		q.pop();
		for (int i = 0; i < 26; ++ i) {
			if (ac[fr].tr[i]) {
				ac[ac[fr].tr[i]].fail = ac[ac[fr].fail].tr[i];
				ac[ac[fr].tr[i]].End |= ac[ac[ac[fr].tr[i]].fail].End;
				q.emplace(ac[fr].tr[i]);
			} else {
				ac[fr].tr[i] = ac[ac[fr].fail].tr[i];
			}
		}
	}
}

ll qpow(int x, int y) {
	ll ans = 1;
	while (y) {
		if (y & 1) {
			ans = ans * x % mod;
		}
		y >>= 1;
		x = x * x % mod;
	}
	return ans % mod;
}

int main() {
	n = read<int>(), m = read<int>();
	for (int i = 1; i <= n; ++ i) {
		scanf("%s", s + 1);
		Insert(s + 1);
	}
	get_fail();
	dp[0][0] = 1;
	for (int i = 1; i <= m; ++ i) {
		for (int j = 0; j <= tot; ++ j) {
			for (int k = 0; k < 26; ++ k) {
				if (!ac[ac[j].tr[k]].End) {
					dp[i][ac[j].tr[k]] = (dp[i - 1][j] + dp[i][ac[j].tr[k]]) % mod;
				}
			} 
		}
	}
	ll ans = qpow(26, m);
	for (int i = 0; i <= tot; ++ i) {
		ans = ((ans - dp[m][i]) % mod + mod) % mod;
	}
	printf("%lld\n", ans);
	return 0;
}

标签:ac,ch,JSOI2007,int,生成器,tr,fr,fail,刷题
From: https://www.cnblogs.com/yifan0305/p/17573497.html

相关文章

  • 代码生成器-根据数据库表
    publicstaticvoidmain(String[]args){//1、创建代码生成器AutoGeneratormpg=newAutoGenerator();//2、全局配置GlobalConfiggc=newGlobalConfig();StringprojectPath=System.getProperty("user.dir");......
  • [刷题记录Day4]Leetcode链表专题
    No.1题目两两交换链表中的节点思路模拟类型题目两个节点前后交换,同时记住原来的下一个节点虚拟头节点代码public ListNode swapPairs(ListNode head) { ListNode dummyHead = new ListNode(-1, head); ListNode cur = dummyHead; while (cur.next != ......
  • mybatis的generator 代码生成器(自动生成DAO,PO,XML)
    1.引入插件<!--mybatis代码自动生成插件--><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><......
  • 【刷题笔记】55. Jump Game
    题目Givenanarrayofnon-negativeintegers,youareinitiallypositionedatthefirstindexofthearray.Eachelementinthearrayrepresentsyourmaximumjumplengthatthatposition.Determineifyouareabletoreachthelastindex.Example1:Input:......
  • [刷题笔记] Luogu P1168 中位数
    ProblemDescription题目描述非常简洁,不作解释。Solution题目要求对前奇数项求中位数?朴素的做法是暴力,但是范围1e5显然T。这里主要介绍一种堆顶堆的做法。堆顶堆是什么呢?我们不妨开两个堆,一个大根堆一个小根堆。动态维护中位数,初始令前1位的中位数为\(a_i\),遍历数组,若遇到比中......
  • [刷题笔记] 异或
    Problem给定一个包含\(n\)个数的可重集,每个数为0或1,初始时答案变量\(ans=0\)。你需要进行\(n-1\)次操作,每次操作进行如下:选取可重集中的两个数\(x,y\),并计算出\(z=x\operatorname{xor}y\)。将\(ans\)增加\(z\)。在可重集中删除\(x,y\),并加入\(z\)......
  • 数据结构刷题
    山理工数据结构刷题专题1--顺序表专题2--栈和队列专题3--串和数组专题4--二叉树专题5--二叉查找树和平衡二叉树树结构练习——排序二叉树的中序遍历#include<bits/stdc++.h>#defineyescout<<"YES"<<'\n'#defineno cout<<"NO"<<'\n'usingnamespace......
  • MyBatis Generator代码生成器
    地址:http://mybatis.org/generator/quickstart.html 依赖<!--mybatis代码生成--><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId>......
  • Python练手小项目——简易版基础SQL模板代码生成器
    1、效果图2、代码源码-ui.py:fromtkinterimport*fromtkinterimportscrolledtext,messageboxfromtkinter.ttkimportComboboximportpymysqldefinit():#创建窗口:实例化一个窗口对象window=Tk()#窗口大小window.geometry("900x550")......
  • leetcode刷题记录Java
    难度等级:简单给你两个字符串word1和word2。请你从word1开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。返回合并后的字符串。classSolution{publicStringmergeAlternately(Stringword1,St......