问题描述:先给你s个禁止串,求不包含禁止串的最长串,如果存在,打印字典序最大。

数据范围:s <= 1000, 禁止串长度不超过50。

分析:不匹配问题实际上等同于匹配问题。假设我们已经有满足条件的串T, 如果加上某个字符c后得到的新串T + c 仍然满足条件,显然

我们便找到了一个更长的串,否则|T|就是所求。我们枚举字符c时,新串是否满足条件取决于原串T的后缀关于所有禁止串在其构成的trie

上的匹配情况,这也就是我们需要并且仅需要维护的信息。具体的说,我们记录串T在trie中匹配最深的节点编号,假设为l(T),当在T尾部

追加字符c时:

l(T) = nex[l(T)][c]

T = T + c

如果更新后得到的l(T)不在任一个禁止节点上,新串便是符合要求的。

如此我们看,若存在一个长度有限的最长串T,那么在T后追加任一个字符c后都会使得l(T + c)落在某个禁止节点上。考虑nex数组的计算:

nex[i][j]表示节点i对应的前缀追加字符j后在trie中匹配最深的节点编号。显然:

nex[i][j] = ch[i][j] ? ch[i][j] : ch[fail[i]][j]]

这里fail[i]表示节点i对应的前缀的后缀(不包括其本身)在trie中匹配最深的节点编号,即AC自动机中的失配函数。

将nex数组合并到ch数组中:

ch[i][j] = nex[i][j]

于是由trie中所有节点关于ch函数构成的一张有向图,并且将某些节点标记为禁止节点当且仅的其对应的前缀为某个禁止串。

因此考虑删去禁止节点后的新图G = (V, A), 合法串与图上的路径有一一对应关系,最长串存在当且仅当 |V| > 1(不能仅包含trie中0节点)

且图中无环。

判断一张有向图是否是DAG可以使用栈的性质,栈中存储dfs搜索经过的链节点,若新点不在链中即可加入,否则证明有环。

 #include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <iostream>
#include <assert.h>
#define pi acos(-1.)
using namespace std;
typedef long long ll;
const int int_inf = 0x3f3f3f3f;
const ll ll_inf = 1ll << ;
const int INT_INF = (int)((1ll << ) - );
const int mod = 1e9 + ;
const double double_inf = 1e30;
typedef unsigned long long ul;
#pragma comment(linker, "/STACK:102400000,102400000")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define mp make_pair
#define st first
#define nd second
#define keyn (root->ch[1]->ch[0])
#define lson (u << 1)
#define rson (u << 1 | 1)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define type(x) __typeof(x.begin())
#define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
#define FOR(i, s, t) for(int i = (s); i <= (t); i++)
#define ROF(i, t, s) for(int i = (t); i >= (s); i--)
#define dbg(x) cout << x << endl
#define dbg2(x, y) cout << x << " " << y << endl
#define clr(x, i) memset(x, (i), sizeof(x))
#define maximize(x, y) x = max((x), (y))
#define minimize(x, y) x = min((x), (y))
#define low_bit(x) ((x) & (-x)) inline int readint(){
int x;
scanf("%d", &x);
return x;
} inline int readstr(char *s){
scanf("%s", s);
return strlen(s);
} class cmpt{
public:
bool operator () (const int &x, const int &y) const{
return x > y;
}
}; int Rand(int x, int o){
//if o set, return [1, x], else return [0, x - 1]
if(!x) return ;
int tem = (int)((double)rand() / RAND_MAX * x) % x;
return o ? tem + : tem;
} void data_gen(){
srand(time());
freopen("in.txt", "w", stdout);
int times = ;
printf("%d\n", times);
while(times--){
int n = Rand(, ), m = Rand(, );
printf("%d %d\n", n, m);
FOR(i, , n){
FOR(j, , m) printf("%c", Rand(, ) + 'a');
putchar('\n');
}
n = Rand(min(, n), ), m = Rand(min(, m), );
printf("%d %d\n", n, m);
FOR(i, , n){
FOR(j, , m) printf("%c", Rand(, ) + 'a');
putchar('\n');
}
}
} struct cmpx{
bool operator () (int x, int y) { return x > y; }
};
int debug = ;
int dx[] = {-, , , };
int dy[] = {, , -, };
//-------------------------------------------------------------------------
const int maxn = 1e3 + ;
const int maxm = ;
int sigma_size, tot;
struct Trie{
int ch[maxn * maxm][];
int sz;
int info[maxn * maxm];
int fail[maxn * maxm];
int ans[maxn * maxm];
int ok[maxn * maxm];
void init() { sz = tot = ; clr(ch[], ); clr(info, ); }
int idx(char c) { return c - 'A'; }
void insert(char *s){
int u = ;
while(*s){
int v = ch[u][idx(*s)];
if(!v) { ch[u][idx(*s)] = v = ++sz; clr(ch[sz], ); }
u = v;
++s;
}
if(!info[u]) info[u] = ++tot;
}
void getFail(){
queue<int> q;
while(!q.empty()) q.pop();
FOR(i, , sigma_size - ) if(ch[][i]) q.push(ch[][i]);
FOR(i, , sigma_size - ) fail[ch[][i]] = ;
while(!q.empty()){
int u = q.front(); q.pop();
FOR(i, , sigma_size - ){
int v = ch[u][i];
if(!v) { ch[u][i] = ch[fail[u]][i]; continue; }
fail[v] = ch[fail[u]][i];
q.push(v);
}
}
} bool vis[maxn * maxm];
bool dfs(int u){
if(vis[u]) return true;
if(ok[u] != -) return ok[u];
if(info[u]) return ok[u] = ;
vis[u] = ;
FOR(i, , sigma_size - ){
int v = ch[u][i];
if(dfs(v)) { vis[u] = ; return ok[u] = ; }
}
vis[u] = ;
return ok[u] = ;
} bool isAcy(){
clr(ok, -), clr(vis, );
return !dfs();
} int __dfs(int u){
if(ans[u] != -) return ans[u];
if(info[u]) return ans[u] = ;
int maxi = ;
FOR(i, , sigma_size - ){
int v = ch[u][i];
int tem = __dfs(v);
maximize(maxi, tem);
}
return ans[u] = maxi + ;
}
int getAns(){
clr(ans, -);
return __dfs();
}
void printAns(int u, int d){
if(info[u]) return;
ROF(i, sigma_size - , ){
int v = ch[u][i];
if(ans[v] == d - ){
if(ans[v] > ) putchar(i + 'A');
printAns(v, d - );
return;
}
}
}
}trie;
int n;
char s[maxm];
//-------------------------------------------------------------------------
int main(){
//data_gen(); return 0;
//C(); return 0;
debug = ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(debug) freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
int T = readint();
while(T--){
sigma_size = readint(), n = readint();
trie.init();
FOR(i, , n){
readstr(s);
trie.insert(s);
}
trie.getFail();
int ans;
if(!trie.isAcy()) ans = ;
else ans = trie.getAns();
if(ans > ) trie.printAns(, ans), putchar('\n');
else puts("No");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
return ;
}

code:

LA 3907 Puzzle的更多相关文章

  1. BZOJ 3907: 网格

    Description 求不跨过直线 \(y=x\) ,到达 \((n,m)\) 的方案数. Sol 组合数学+高精度. 这个推导过程跟 \(Catalan\) 数是一样的. 答案就是 \(C^{n+ ...

  2. POJ 1651 Mulitiplication Puzzle

    The multiplication puzzle is played with a row of cards, each containing a single positive integer. ...

  3. Puzzle 面向服务/切面(AOP/IOC)开发框架 For .Net

    Puzzle 面向服务/切面AOP开发框架 For .Net AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效 ...

  4. leggere la nostra recensione del primo e del secondo

    La terra di mezzo in trail running sembra essere distorto leggermente massima di recente, e gli aggi ...

  5. Le lié à la légèreté semblait être et donc plus simple

    Il est toutefois vraiment à partir www.runmasterfr.com/free-40-flyknit-2015-hommes-c-1_58_59.html de ...

  6. HDU5456 Matches Puzzle Game(DP)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5456 Description As an exciting puzzle game for ...

  7. one recursive approach for 3, hdu 1016 (with an improved version) , permutations, N-Queens puzzle 分类: hdoj 2015-07-19 16:49 86人阅读 评论(0) 收藏

    one recursive approach to solve hdu 1016, list all permutations, solve N-Queens puzzle. reference: t ...

  8. poj3678 Katu Puzzle 2-SAT

    Katu Puzzle Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6714   Accepted: 2472 Descr ...

  9. POJ1651Multiplication Puzzle[区间DP]

    Multiplication Puzzle Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8737   Accepted:  ...

随机推荐

  1. Java String类详解

    Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...

  2. CPU informition

    tar jxvf util-linux-ng-2.18.bz2cd util-linux-ng-2.18/./configure --enable-arch --enable-partx --enab ...

  3. acm pc^2的配置与使用

    -------------------------------------------------------------------------------------- !!! 转载请注明: 转自 ...

  4. ACRush 楼天成回忆录

    楼教主回忆录: 利用假期空闲之时,将这几年 GCJ , ACM , TopCoder 参加的一些重要比赛作个回顾.首先是 GCJ2006 的回忆. Google Code Jam 2006 一波三折: ...

  5. Python学习总结8:文件模式及操作方法汇总

    文件操作之前需要文件保证文件存在,并且将文件open os.mknod("test.txt")        创建空文件 fp = open("test.txt" ...

  6. Android Handler简单使用

    package com.example.myhandlertest3; import android.os.Bundle; import android.os.Handler; import andr ...

  7. [转]iis7.5+win2008 出现 HTTP Error 503. The service is unavailable.

    解决: 应用程序池启动32位应用程序 设置托管管道为集成 (仍然有问题) 试试以下方法: http://phpwind.me/1222.html 楼主  发表于: 2011-11-26     图片: ...

  8. DDR3简介(一)

    JEDEC成立于1958年,作为电子产业协会联盟(EIA)的一部分,为新兴的半导体产业制定标准.主要功能包括术语定义,产品特征描述,测试方法,固态存储器,DRAM,闪存卡及射频识别标签等的确定与标准化 ...

  9. 超链接点击后不显示hover

    超链接访问过后 hover 样式就不出现了,被点击访问过的超链接样式不在具有 hover 和 active 了 解决方法:改变CSS属性的排列顺序 L-V-H-A a:link {} a:visite ...

  10. fork系统调用(转载)

    (1) fork系统调用说明 fork系统调用用于从已存在进程中创建一个新进程,新进程称为子进程,而原进程称为父进程.fork调用一次,返回两次,这两个返回分别带回它们各自的返回值,其中在父进程中的返 ...