LA 3907 Puzzle

 

问题描述:先给你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搜索经过的链节点,若新点不在链中即可加入,否则证明有环。

  1 #include <algorithm>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <queue>
  6 #include <map>
  7 #include <set>
  8 #include <ctime>
  9 #include <cmath>
 10 #include <iostream>
 11 #include <assert.h>
 12 #define pi acos(-1.)
 13 using namespace std;
 14 typedef long long ll;
 15 const int int_inf = 0x3f3f3f3f;
 16 const ll ll_inf = 1ll << 62;
 17 const int INT_INF = (int)((1ll << 31) - 1);
 18 const int mod = 1e9 + 7;
 19 const double double_inf = 1e30;
 20 typedef unsigned long long ul;
 21 #pragma comment(linker, "/STACK:102400000,102400000")
 22 #define max(a, b) ((a) > (b) ? (a) : (b))
 23 #define min(a, b) ((a) < (b) ? (a) : (b))
 24 #define mp make_pair
 25 #define st first
 26 #define nd second
 27 #define keyn (root->ch[1]->ch[0])
 28 #define lson (u << 1)
 29 #define rson (u << 1 | 1)
 30 #define pii pair<int, int>
 31 #define pll pair<ll, ll>
 32 #define pb push_back
 33 #define type(x) __typeof(x.begin())
 34 #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
 35 #define FOR(i, s, t) for(int i = (s); i <= (t); i++)
 36 #define ROF(i, t, s) for(int i = (t); i >= (s); i--)
 37 #define dbg(x) cout << x << endl
 38 #define dbg2(x, y) cout << x << " " << y << endl
 39 #define clr(x, i) memset(x, (i), sizeof(x))
 40 #define maximize(x, y) x = max((x), (y))
 41 #define minimize(x, y) x = min((x), (y))
 42 #define low_bit(x) ((x) & (-x))
 43 
 44 inline int readint(){
 45     int x;
 46     scanf("%d", &x);
 47     return x;
 48 }
 49 
 50 inline int readstr(char *s){
 51     scanf("%s", s);
 52     return strlen(s);
 53 }
 54 
 55 class cmpt{
 56 public:
 57     bool operator () (const int &x, const int &y) const{
 58         return x > y;
 59     }
 60 };
 61 
 62 int Rand(int x, int o){
 63     //if o set, return [1, x], else return [0, x - 1]
 64     if(!x) return 0;
 65     int tem = (int)((double)rand() / RAND_MAX * x) % x;
 66     return o ? tem + 1 : tem;
 67 }
 68 
 69 void data_gen(){
 70     srand(time(0));
 71     freopen("in.txt", "w", stdout);
 72     int times = 10;
 73     printf("%d\n", times);
 74     while(times--){
 75         int n = Rand(500, 1), m = Rand(500, 1);
 76         printf("%d %d\n", n, m);
 77         FOR(i, 1, n){
 78             FOR(j, 1, m) printf("%c", Rand(2, 0) + 'a');
 79             putchar('\n');
 80         }
 81         n = Rand(min(10, n), 1), m = Rand(min(10, m), 1);
 82         printf("%d %d\n", n, m);
 83         FOR(i, 1, n){
 84             FOR(j, 1, m) printf("%c", Rand(2, 0) + 'a');
 85             putchar('\n');
 86         }
 87     }
 88 }
 89 
 90 struct cmpx{
 91     bool operator () (int x, int y) { return x > y; }
 92 };
 93 int debug = 1;
 94 int dx[] = {-1, 1, 0, 0};
 95 int dy[] = {0, 0, -1, 1};
 96 //-------------------------------------------------------------------------
 97 const int maxn = 1e3 + 10;
 98 const int maxm = 55;
 99 int sigma_size, tot;
100 struct Trie{
101     int ch[maxn * maxm][26];
102     int sz;
103     int info[maxn * maxm];
104     int fail[maxn * maxm];
105     int ans[maxn * maxm];
106     int ok[maxn * maxm];
107     void init() { sz = tot = 0; clr(ch[0], 0); clr(info, 0); }
108     int idx(char c) { return c - 'A'; }
109     void insert(char *s){
110         int u = 0;
111         while(*s){
112             int v = ch[u][idx(*s)];
113             if(!v) { ch[u][idx(*s)] = v = ++sz; clr(ch[sz], 0); }
114             u = v;
115             ++s;
116         }
117         if(!info[u]) info[u] = ++tot;
118     }
119     void getFail(){
120         queue<int> q;
121         while(!q.empty()) q.pop();
122         FOR(i, 0, sigma_size - 1) if(ch[0][i]) q.push(ch[0][i]);
123         FOR(i, 0, sigma_size - 1) fail[ch[0][i]] = 0;
124         while(!q.empty()){
125             int u = q.front(); q.pop();
126             FOR(i, 0, sigma_size - 1){
127                 int v = ch[u][i];
128                 if(!v) { ch[u][i] = ch[fail[u]][i]; continue; }
129                 fail[v] = ch[fail[u]][i];
130                 q.push(v);
131             }
132         }
133     }
134 
135     bool vis[maxn * maxm];
136     bool dfs(int u){
137         if(vis[u]) return true;
138         if(ok[u] != -1) return ok[u];
139         if(info[u]) return ok[u] = 0;
140         vis[u] = 1;
141         FOR(i, 0, sigma_size - 1){
142             int v = ch[u][i];
143             if(dfs(v)) { vis[u] = 0; return ok[u] = 1; }
144         }
145         vis[u] = 0;
146         return ok[u] = 0;
147     }
148 
149     bool isAcy(){
150         clr(ok, -1), clr(vis, 0);
151         return !dfs(0);
152     }
153 
154     int __dfs(int u){
155         if(ans[u] != -1) return ans[u];
156         if(info[u]) return ans[u] = 0;
157         int maxi = 0;
158         FOR(i, 0, sigma_size - 1){
159             int v = ch[u][i];
160             int tem = __dfs(v);
161             maximize(maxi, tem);
162         }
163         return ans[u] = maxi + 1;
164     }
165     int getAns(){
166         clr(ans, -1);
167         return __dfs(0);
168     }
169     void printAns(int u, int d){
170         if(info[u]) return;
171         ROF(i, sigma_size - 1, 0){
172             int v = ch[u][i];
173             if(ans[v] == d - 1){
174                 if(ans[v] > 0) putchar(i + 'A');
175                 printAns(v, d - 1);
176                 return;
177             }
178         }
179     }
180 }trie;
181 int n;
182 char s[maxm];
183 //-------------------------------------------------------------------------
184 int main(){
185     //data_gen(); return 0;
186     //C(); return 0;
187     debug = 0;
188     ///
189     if(debug) freopen("in.txt", "r", stdin);
190     //freopen("out.txt", "w", stdout);
191     int T = readint();
192     while(T--){
193         sigma_size = readint(), n = readint();
194         trie.init();
195         FOR(i, 1, n){
196             readstr(s);
197             trie.insert(s);
198         }
199         trie.getFail();
200         int ans;
201         if(!trie.isAcy()) ans = 0;
202         else ans = trie.getAns();
203         if(ans > 1) trie.printAns(0, ans), putchar('\n');
204         else puts("No");
205     }
206     //
207     return 0;
208 }
code:

 

转载于:https://www.cnblogs.com/astoninfer/p/5695522.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值