题意:有F个单词,1 <= F <=60 , 长度<=10^4, 每次可以输入一个字符串,所有包含该字串的单词会形成一个集合。

问最多能形成多少个不同的集合。集合不能为空。

分析:用后缀数组处理。然后首先考虑一个单词形成一个集合的情况,若该单词是其他单词的字串,则该单词显然不会形成一个集合,那么利用后缀数组,

对于每个单词看能否与其他单词有LCP,且LCP 长度为该单词本身长度。

然后就是多个单词形成集合的情况:比较简单的处理方式就是将h数组值相同的下标集中存储,比如h[x] = h[y] = h[z] = 5, 那么将x,y,z存到h

值对应为5的数组中,然后按照h值,假设为v,从大到小的顺序,将所有h值为v的下标与其周围的LCP大于v的(h[v-1],h[v])对应的子串,更新并查集。实际意义就是,每次将h值为h[v]的一些子串所在的单词合并到之前h值> h[v]的子串所在的单词形成的并查集中,得到的并查集中单词一定有长度>=h[v]公共字串,这样的并查集实际就是一个合法的单词集合,可以利用二进制表示,每次得到新的集合则将二进制表示加入到统计集合的set中,最后结果就是set的大小。

AC代码其实是比赛时写的,当时多个单词部分不是上面这种写法,不过类似。

 #include <bits/stdc++.h>
#define in freopen("solve_in.txt", "r", stdin);
#define bug(x) printf("Line %d:>>>>>>>\n", (x)); #define REV(a) reverse((a).begin(), (a).end())
#define READ(a, n) {REP(i, n) cin>>(a)[i];}
#define REP(i, n) for(int i = 0; i < (n); i++)
#define VREP(i, n, base) for(int i = (n); i >= (base); i--)
#define Rep(i, base, n) for(int i = (base); i < (n); i++)
#define REPS(s, i) for(int i = 0; (s)[i]; i++)
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef map<ULL, int> UMps;
set<ULL> se; const int maxn = + ;
const int maxm = ;
const int maxlen = maxn*maxm+;
int s[maxlen];
int sa[maxlen], t[maxlen], t2[maxlen], c[maxlen], n, m, dp[maxlen][];
int num[maxlen];
LL ans;
void build_sa(int m) {
int *x = t, *y = t2; REP(i, m) c[i] = ;
REP(i, n) c[x[i] = s[i]]++;
Rep(i, , m) c[i] += c[i-];
VREP(i, n-, ) sa[--c[x[i]]] = i; for(int k = ; k <= n; k <<= ) {
int p = ; Rep(i, n-k, n) y[p++] = i;
REP(i, n) if(sa[i] >= k) y[p++] = sa[i]-k; REP(i, m) c[i] = ;
REP(i, n) c[x[y[i]]]++;
Rep(i, , m) c[i] += c[i-]; VREP(i, n-, ) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = , x[sa[]] = ;
Rep(i, , n)
x[sa[i]] = y[sa[i-]] == y[sa[i]] && y[sa[i-]+k] == y[sa[i]+k] ? p- : p++;
if(p >= n) break;
m = p;
}
}
int rk[maxlen], h[maxlen]; void getHeight() {
int j, k = ;
h[] = ;
REP(i, n) rk[sa[i]] = i;
REP(i, n) {
if(k) k--;
if(rk[i] == )
continue;
j = sa[rk[i]-];
while( s[i+k] == s[j+k]) k++;
h[rk[i]] = k;
}
}
void RMQ_init() {
REP(i, n) dp[i][] = h[i];
for(int k = ; (<<k) <= n; k++)
for(int i = ; i + (<<k) <= n; i++)
dp[i][k] = min(dp[i][k-], dp[i+(<<(k-))][k-]);
}
int RMQ(int l, int r) {
int k = ;
while((<<(k+)) <= r-l+) k++;
return min(dp[l][k], dp[r-(<<k)+][k]);
}
char word[maxm][maxn];
int nn;
inline int idx(char ch) {
return ch-'a'+;
}
int vis[], slen[]; void solveSingle() {
se.clear();
memset(vis, , sizeof vis);
for(int i = ; i < n; i++){
if(h[i]){
if(num[sa[i]] != - && h[i] == slen[num[sa[i]]])
vis[num[sa[i]]] = ;
if(num[sa[i-]] != - && h[i] == slen[num[sa[i-]]])
vis[num[sa[i-]]] = ;
}
}
for(int i = ; i < nn; i++) if(!vis[i])
se.insert(1ULL<<i);
}
void dfs(int l, int r, int now) {
if(l >= r)
return;
ULL tmp; for(int i = l; i < r; ) {
tmp = ;
while(i < r && h[i] <= now)
i++;
if(i >= r)
break;
int mx = (int)1e9;
int j = i;
mx = min(mx, h[j]);
if(j < r && num[sa[j-]] != -)
tmp |= 1ULL<<num[sa[j-]];
while(j < r && h[j] > now) {
mx = min(mx, h[j]);
if(num[sa[j]] != -)
tmp |= 1ULL<<num[sa[j]];
j++;
}
if(tmp)
se.insert(tmp);
dfs(i, j, mx);
i = j;
}
}
void solve() {
build_sa();
getHeight();
solveSingle();
ULL tmp;
for(int i = ; i < n; ) {
int mx = (int)1e9;
tmp = ;
while(i < n && !h[i])
i++;
if(i >= n)
break;
mx = min(mx, h[i]);
int j = i;
if(j < n && num[sa[j-]] != -)
tmp |= 1ULL<<num[sa[j-]];
while(j < n && h[j]) {
mx = min(mx, h[j]);
if(num[sa[j]] != -)
tmp |= 1ULL<<num[sa[j]];
j++;
}
if(tmp)
se.insert(tmp);
dfs(i, j, mx);
i = j;
}
printf("%llu\n", (ULL)se.size());
}
int main() { while(scanf("%d", &nn), nn) {
n = ;
memset(num, -, sizeof num);
for(int i = ; i < nn; i++) {
slen[i] = ;
scanf("%s", word[i]);
for(int j = ; word[i][j]; j++) {
slen[i]++;
s[n] = idx(word[i][j]);
num[n++] = i;
}
s[n++] = +i;
}
s[n-] = ;
solve();
}
return ;
}

Uva 12361 File Retrieval 后缀数组+并查集的更多相关文章

  1. BZOJ 4566 JZYZOJ 1547 [haoi2016T5]找相同子串 后缀数组 并查集

    http://172.20.6.3/Problem_Show.asp?id=1547 http://www.lydsy.com/JudgeOnline/problem.php?id=4566 单纯后缀 ...

  2. NOI 2015 品酒大会 (后缀数组+并查集)

    题目大意:略 40分暴力还是很好写的,差分再跑个后缀和 和 后缀最大值就行了 一种正解是后缀数组+并查集 但据说还有后缀数组+单调栈的高端操作蒟蒻的我当然不会 后缀数组求出height,然后从大到小排 ...

  3. [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  4. BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )

    求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ------------------------- ...

  5. 【学术篇】NOI2015 品酒大会 后缀数组+并查集

    省选前大致是刷不了几道题了... 所以就找一些裸一点的题目练练板子算了= = 然而这题一点都不裸, 也并不怎么好写... 于是就浪费了将近一下午的时间... 然而还不是因为后缀数组板子不熟= = 首先 ...

  6. POJ 3415 Common Substrings 后缀数组+并查集

    后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height   求完之后按height值从大往小合并.  height值代表的是  sa[i]和sa[i ...

  7. 4199. [NOI2015]品酒大会【后缀数组+并查集】

    Description 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加.在大会的晚餐上,调酒师 ...

  8. 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

    [BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...

  9. loj6198谢特 后缀数组+并查集+Trie

    先把问题放在后缀数组上考虑 已知两个数组a b,求min(a[i],...,a[j])+(b[i]^b[j])的最大值 套路题 初始每个点都是一个小连通块 把a按从大到小的顺序加入,计算当前加入边作为 ...

随机推荐

  1. JAXB - Annotations, Controlling Element Selection: XmlAccessorType, XmlTransient

    If JAXB binds a class to XML, then, by default, all public members will be bound, i.e., public gette ...

  2. Appium Android 屏幕滑动

  3. java中内部类的定义与访问规则

    java内部类总结 简单来说,内部类就是在我们所熟悉的类中的里面再定义一个类 为什么需要内部类? 当我们描述事物时,事物之中还有事物,我们就用内部类描述事物 因为内部事物在使用外部事物的内容 我举一个 ...

  4. C语言 宏/macor/#define/

    C语言 宏/macor/#define 高级技巧 1.在进行调试的时候,需要进行打印/PRINT,可以通过define进行自定义.例如,自己最常用的DEBUG_PRINT() #define DEBU ...

  5. Wix: Show conditional message box

    For example: Scenario: Show message box only during installation and MYPROPERTY has to be equal to & ...

  6. PHP学习笔记——上传文件到服务端的文件夹下

    环境 开发包:appserv-win32-2.5.10 服务器:Apache2.2 数据库:phpMyAdmin 语言:php5,java 平台:windows 10 需求 编写一个PHP脚本页面,可 ...

  7. Web前端新人笔记之height、min-height的区别

     浏览器参照基准:Firefox, Chrome, Safari, Opera, IE: * IE6不支持CSS min-height属性.最小高度的定义:1. 元素拥有默认高度:2. 当内容超出元素 ...

  8. 替换a链接的href和title

    新项目准备验收,客户检测网页有安全隐患,说是当前网页使用“http://”有风险,指定外部链接不用“http://”怎么整…… 后来想到用JS替换字符串去操作,找了半天总算找到合用的,最终是用JQ去更 ...

  9. JS访问Struts 2 ValueStack中的内容

    /* * var myArray = new Array("${vacant[0]}", "${vacant[1]}", "${vacant[2]}& ...

  10. MVC-ActionResult解说

    HttpNotFoundResult: 专门用来响应Http404找不到网页的错误,在System.Web.Mvc.Controller类别中内建了一个HttpNotFound()方法,可以很方便的回 ...