POJ 1625 Censored!(AC自动机 + DP + 大数 + 拓展ASCII处理)题解
题意:给出n个字符,p个病毒串,要你求出长度为m的不包含病毒串的主串的个数
思路:不给取模最恶劣情况$50^{50}$,所以用高精度板子。因为m比较小,可以直接用DP写。
因为给你的串的字符包含拓展ASCII码(128~256),由于编译器的原因,char的读入范围在-128~127或者0~255之间不确定,所以你读一个拓展ASCII码的字符后可能是负的,那么你处理的时候要注意加130。或者你直接用map映射。或者用unsigned char。
代码:
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100 + 5;
const int M = 50 + 5;
const ull seed = 131;
const double INF = 1e20;
const int MOD = 100000;
int n, m, p;
int tol;
int reflect[600];
struct BigInt{
const static int mod = 10000;
int a[50], len;
BigInt(){
memset(a, 0, sizeof(a));
len = 1;
}
void set(int v){
memset(a, 0, sizeof(a));
len = 0;
do{
a[len++] = v % mod;
v /= mod;
}while(v);
} BigInt operator + (const BigInt &b) const{
BigInt res;
res.len = max(len, b.len);
for(int i = 0; i <= res.len; i++)
res.a[i] = 0;
for(int i = 0; i < res.len; i++){
res.a[i] += ((i < len)? a[i] : 0) + ((i < b.len)? b.a[i] : 0);
res.a[i + 1] += res.a[i] / mod;
res.a[i] %= mod;
}
if(res.a[res.len] > 0) res.len++;
return res;
} BigInt operator * (const BigInt &b) const{
BigInt res;
for(int i = 0; i < len; i++){
int up = 0;
for(int j = 0; j < b.len; j++){
int temp = a[i] * b.a[j] + res.a[i + j] + up;
res.a[i + j] = temp % mod;
up = temp / mod;
}
if(up != 0) res.a[i + b.len] = up;
}
res.len = len + b.len;
while(res.a[res.len - 1] == 0 && res.len > 1) res.len--;
return res;
} void output(){
printf("%d", a[len - 1]);
for(int i = len - 2; i >= 0; i--){
printf("%04d", a[i]);
}
printf("\n");
}
};
BigInt dp[55][maxn];
struct Aho{
struct state{
int next[51];
int fail, cnt;
}node[maxn];
int size;
queue<int> q; void init(){
size = 0;
newtrie();
while(!q.empty()) q.pop();
} int newtrie(){
memset(node[size].next, 0, sizeof(node[size].next));
node[size].cnt = node[size].fail = 0;
return size++;
} void insert(char *s){
int len = strlen(s);
int now = 0;
for(int i = 0; i < len; i++){
int c = reflect[int(s[i]) + 130];
if(node[now].next[c] == 0){
node[now].next[c] = newtrie();
}
now = node[now].next[c];
}
node[now].cnt = 1;
} void build(){
node[0].fail = -1;
q.push(0); while(!q.empty()){
int u = q.front();
q.pop();
if(node[node[u].fail].cnt && u) node[u].cnt = 1;
for(int i = 0; i < 51; i++){
if(!node[u].next[i]){
if(u == 0)
node[u].next[i] = 0;
else
node[u].next[i] = node[node[u].fail].next[i];
}
else{
if(u == 0) node[node[u].next[i]].fail = 0;
else{
int v = node[u].fail;
while(v != -1){
if(node[v].next[i]){
node[node[u].next[i]].fail = node[v].next[i];
break;
}
v = node[v].fail;
}
if(v == -1) node[node[u].next[i]].fail = 0;
}
q.push(node[u].next[i]);
}
}
}
} void query(){
BigInt one;
one.set(1);
for(int i = 0; i <= m; i++){
for(int j = 0; j < size; j++){
dp[i][j].set(0);
}
}
for(int i = 0; i < tol; i++){
if(node[node[0].next[i]].cnt == 0){
dp[1][node[0].next[i]] = dp[1][node[0].next[i]] + one;
}
}
for(int i = 1; i <= m; i++){
for(int j = 0; j < size; j++){
for(int k = 0; k < tol; k++){
if(node[node[j].next[k]].cnt == 0){
dp[i + 1][node[j].next[k]] = dp[i + 1][node[j].next[k]] + dp[i][j];
}
}
}
}
BigInt ans;
ans.set(0);
for(int i = 0; i < size; i++){
if(node[i].cnt == 0){
ans = ans + dp[m][i];
}
}
ans.output();
} }ac;
char s[100];
int main(){
while(~scanf("%d%d%d", &n, &m, &p)){
scanf("%s", s);
tol = 0;
for(int i = 0; i < n; i++){
reflect[int(s[i]) + 130] = tol++;
}
ac.init();
while(p--){
scanf("%s", s);
ac.insert(s);
}
ac.build();
ac.query();
}
return 0;
}
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100 + 5;
const int M = 50 + 5;
const ull seed = 131;
const double INF = 1e20;
const int MOD = 100000;
int n, m, p;
int tol;
map<char, int> reflect;
struct BigInt{
const static int mod = 10000;
int a[50], len;
BigInt(){
memset(a, 0, sizeof(a));
len = 1;
}
void set(int v){
memset(a, 0, sizeof(a));
len = 0;
do{
a[len++] = v % mod;
v /= mod;
}while(v);
} BigInt operator + (const BigInt &b) const{
BigInt res;
res.len = max(len, b.len);
for(int i = 0; i <= res.len; i++)
res.a[i] = 0;
for(int i = 0; i < res.len; i++){
res.a[i] += ((i < len)? a[i] : 0) + ((i < b.len)? b.a[i] : 0);
res.a[i + 1] += res.a[i] / mod;
res.a[i] %= mod;
}
if(res.a[res.len] > 0) res.len++;
return res;
} BigInt operator * (const BigInt &b) const{
BigInt res;
for(int i = 0; i < len; i++){
int up = 0;
for(int j = 0; j < b.len; j++){
int temp = a[i] * b.a[j] + res.a[i + j] + up;
res.a[i + j] = temp % mod;
up = temp / mod;
}
if(up != 0) res.a[i + b.len] = up;
}
res.len = len + b.len;
while(res.a[res.len - 1] == 0 && res.len > 1) res.len--;
return res;
} void output(){
printf("%d", a[len - 1]);
for(int i = len - 2; i >= 0; i--){
printf("%04d", a[i]);
}
printf("\n");
}
};
BigInt dp[55][maxn];
struct Aho{
struct state{
int next[51];
int fail, cnt;
}node[maxn];
int size;
queue<int> q; void init(){
size = 0;
newtrie();
while(!q.empty()) q.pop();
} int newtrie(){
memset(node[size].next, 0, sizeof(node[size].next));
node[size].cnt = node[size].fail = 0;
return size++;
} void insert(char *s){
int len = strlen(s);
int now = 0;
for(int i = 0; i < len; i++){
int c = reflect[s[i]];
if(node[now].next[c] == 0){
node[now].next[c] = newtrie();
}
now = node[now].next[c];
}
node[now].cnt = 1;
} void build(){
node[0].fail = -1;
q.push(0); while(!q.empty()){
int u = q.front();
q.pop();
if(node[node[u].fail].cnt && u) node[u].cnt = 1;
for(int i = 0; i < 51; i++){
if(!node[u].next[i]){
if(u == 0)
node[u].next[i] = 0;
else
node[u].next[i] = node[node[u].fail].next[i];
}
else{
if(u == 0) node[node[u].next[i]].fail = 0;
else{
int v = node[u].fail;
while(v != -1){
if(node[v].next[i]){
node[node[u].next[i]].fail = node[v].next[i];
break;
}
v = node[v].fail;
}
if(v == -1) node[node[u].next[i]].fail = 0;
}
q.push(node[u].next[i]);
}
}
}
} void query(){
BigInt one;
one.set(1);
for(int i = 0; i <= m; i++){
for(int j = 0; j < size; j++){
dp[i][j].set(0);
}
}
for(int i = 0; i < tol; i++){
if(node[node[0].next[i]].cnt == 0){
dp[1][node[0].next[i]] = dp[1][node[0].next[i]] + one;
}
}
for(int i = 1; i <= m; i++){
for(int j = 0; j < size; j++){
for(int k = 0; k < tol; k++){
if(node[node[j].next[k]].cnt == 0){
dp[i + 1][node[j].next[k]] = dp[i + 1][node[j].next[k]] + dp[i][j];
}
}
}
}
BigInt ans;
ans.set(0);
for(int i = 0; i < size; i++){
if(node[i].cnt == 0){
ans = ans + dp[m][i];
}
}
ans.output();
} }ac;
char s[100];
int main(){
while(~scanf("%d%d%d", &n, &m, &p)){
scanf("%s", s);
tol = 0;
for(int i = 0; i < n; i++){
reflect[s[i]] = tol++;
}
ac.init();
while(p--){
scanf("%s", s);
ac.insert(s);
}
ac.build();
ac.query();
}
return 0;
}
POJ 1625 Censored!(AC自动机 + DP + 大数 + 拓展ASCII处理)题解的更多相关文章
- POJ 1625 Censored!(AC自动机+DP+高精度)
Censored! Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 6956 Accepted: 1887 Descrip ...
- POJ1625 Censored! —— AC自动机 + DP + 大数
题目链接:https://vjudge.net/problem/POJ-1625 Censored! Time Limit: 5000MS Memory Limit: 10000K Total S ...
- POJ 1625 Censored! [AC自动机 高精度]
Censored! Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 9793 Accepted: 2686 Descrip ...
- Match:Censored!(AC自动机+DP+高精度)(POJ 1625)
Censored! 题目大意:给定一些字符,将这些字符组成一个固定长度的字符串,但是字符串不能包含一些禁词,问你有多少种组合方式. 这是一道好题,既然出现了“一些”禁词,那么这题肯定和AC自动机有点 ...
- poj 1625 (AC自动机好模版,大数好模版)
题目 给n个字母,构成长度为m的串,总共有n^m种.给p个字符串,问n^m种字符串中不包含(不是子串)这p个字符串的个数. 将p个不能包含的字符串建立AC自动机,每个结点用val值来标记以当前节点为后 ...
- POJ 1625 Censored ( Trie图 && DP && 高精度 )
题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种? 分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中 ...
- [POJ1625]Censored!(AC自动机+DP+高精度)
Censored! Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 10824 Accepted: 2966 Descri ...
- 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂
[题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...
- POJ1625 Censored!(AC自动机+DP)
题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...
随机推荐
- 3A限流IC,带短路保护,PW1503和PW1502
一般说明 PW1503,PW1502是超低RDS(ON)开关,具有可编程的电流限制,以保护电源源于过电流和短路保护.它具有超温保护以及反向闭锁功能. PW1503,PW1502采用薄型(1毫米)5针薄 ...
- scrapy框架基于管道的持久化存储
scrapy框架的使用 基于管道的持久化存储的编码流程 在爬虫文件中数据解析 将解析到的数据封装到一个叫做Item类型的对象 将item类型的对象提交给管道 管道负责调用process_item的方法 ...
- Flask的配置文件加载两种方式
配置文件 1 基于全局变量 2 基于类的方式 配置文件的加载需要将配合文件的相对路径添加到app.config.from_object("文件路径"),类的方式也是一样,需要将类的 ...
- XShell的手动直连,避免配置ssh免密的一些问题
- 线上一次大量 CLOSE_WAIT 复盘
https://mp.weixin.qq.com/s/PfM3hEsDa3CMLbbKqis-og 线上一次大量 CLOSE_WAIT 复盘 原创 ms2008 poslua 2019-07-05 最 ...
- linux 文件结构体和文件描述符号的学习
https://blog.csdn.net/cywosp/article/details/38965239
- Axure RP 9版本最新版授权码和密钥 亲测可用
分享Axure RP 9版本最新版授权码和密钥 亲测可用 声明:以下资源的获取来源为网络收集,仅供学习参考,不作商业用途,如有侵权请联系博主删除,谢谢! 自新的Axure RP 9.0 Beta版发布 ...
- CF413C
正文 题意: 给 n 个关卡,每个关卡得分为 ai,有 m 次机会可以选择一 个关卡通过后不得分,而将现有得分翻倍 你可以安排关卡的通过顺序和策略,求最大得分. 分析: 看到这道题首先想到的就是贪心, ...
- List对象集合根据组合属性进行差集运算
背景 当List是一个基本数据类型的集合的时候,进行集合运算还比较方便,但是有这么一些业务场景,比如某个用户权限变化的列表,或者取数据的变化结果,当时有时候用笨方法多循环两次也是可以的,只不过代码 ...
- 常用DOS命令及其用法
md 1.作用:建立子目录 2.用法:md [盘符:] [路径名] ①盘符:指定要建立子目录的磁盘驱动器字母,若省略,则为当前驱动器: ②路径名:要建立的子目录的上级目录名,若缺省则建在当前目 ...