问题描述:先给你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. linux:指令与档案的搜索

    linux下的五种搜索方法(参考自鸟哥linux私房菜基础篇): 一.find :功能很强大,直接搜寻整个硬碟的(速度不是很快,如果系统硬碟较旧的话)----特色:find后面可以接多个目录搜索,它本 ...

  2. Redis:安装

    此篇文章并不介绍linux下安装方法.围绕windows安装而介绍 两种安装方式: 1)下载压缩包,解压后(运行起来有个窗口,关闭掉就不在运行),没有windows服务被注册:可以只用命令在cmd将其 ...

  3. Jenkins自动构建

    Jenkins is an award-winning, cross-platform, continuous integration and continuous delivery applicat ...

  4. Lintcode: Rotate String

    Given a string and an offset, rotate string by offset. (rotate from left to right) Example Given &qu ...

  5. 源码安装nginx以及平滑升级

                                                           源码安装nginx以及平滑升级                               ...

  6. spring纯java注解式开发(一)

    习惯了用XML文件来配置spring,现在开始尝试使用纯java代码来配置spring. 其实,spring的纯java配置,简单来说就是将bean标签的内容通过注解转换成bean对象的过程,没什么神 ...

  7. C++之路进阶——优先队列优化最短路径算法(dijkstra)

    一般的dijkstra算法利用贪心的思想,每次找出最短边,然后优化到其他点的的距离,我们还采用贪心思路,但在寻找最短边进行优化,之前是双重for循环,现在我们用优先队列来实现. 代码解释: //样例程 ...

  8. java的I/O操作:文件的路径

    package solutions; import java.io.*; /** * Created by Administrator on 2016/3/14. */ public class Re ...

  9. JSTL标签,EL表达式,OGNL表达式,struts2标签 汇总

    一下纯属个人总结摘抄,总结一起方便查看,解决疑问,有遗漏或错误,还请指出.       1,JSTL标签总结: a).JSTL标签有什么用?          JSTL是由JCP(Java Commu ...

  10. 编译php时的一个脚本

    ./configure --prefix=/usr/local/php \ --with-curl \ --with-freetype-dir \ --with-gd \ --with-gettext ...