题意:有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. JSON数据理解

    话说JSON数据平常用的确实挺多的,但是基本上只知道怎么用,对其一些细节并没有整理过,今儿趁着下午有点空,坐下来,学习整理下,并分享出来. 对于JSON,首先它只是一种数据格式,并非一种语言,虽然和j ...

  2. MySQL 세자리 마다 콤마 찍기

    MySQL에서 세자리 마다 콤마를 찍으려면 FORMAT 함수를 이용하시면 됩니다. FORMAT( 컬럼명, 소수점이하 자리수 ) 여기서 컬럼의 자료형이 varchar와 같은 문자형이 ...

  3. Apache Shiro 使用手册

    http://kdboy.iteye.com/blog/1154644 (一)Shiro架构介绍 一.什么是Shiro  Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加 ...

  4. ASP.NET 4.0 来了

    伴随着VS2010的公开测试,ASP.NET4.0也进入了我们的视线.ASP.NET4.0究竟给我们带来了什么,将在哪些方面提高我们的生产力? 在何时你需要使用ASP.NET4.0开发你的网站程序? ...

  5. php连接Access数据库的三种方法

    http://www.php100.com/html/webkaifa/PHP/PHPyingyong/2009/1115/3524.html 虽然不是一个类但先放这儿吧 最近想把一个asp的网站改成 ...

  6. iOS block的使用

    明明知道block是一个很重要的知识点,很久不用就又忘了,这是在网上看到的一个例子.(晚上回去整理另外的一个) 在视图A上有一个按钮(用来在点击的时候推出视图b)和一个label(用来显示从b传回来的 ...

  7. JavaScript DOM编程艺术 - 读书笔记1-3章

    1.JavaScript语法 准备工作 一个普通的文本编辑器,一个Web浏览器. JavaScript代码必须通过Html文档才能执行,第一种方式是将JavaScript代码放到文档<head& ...

  8. 一种c#深拷贝方式完胜java深拷贝(实现上的对比)

    楼主是一名asp.net攻城狮,最近经常跑java组客串帮忙开发,所以最近对java的一些基础知识特别上心.却遇到需要将一个对象深拷贝出来做其他事情,而原对象保持原有状态的情况.(实在是不想自己new ...

  9. Java实战之04JavaWeb-08文件上传与下载

    一.文件上传 1.文件上传的实质是什么 文件的拷贝,文件从客户端拷贝服务器端 2.文件上传的工作 (1)客户端怎样将本地文件输出去? 1)文件上传的表单项 <input type=”file”& ...

  10. hdu 1063 Exponentiation (高精度小数乘法)

    //大数继续,额,要吐了. Problem Description Problems involving the computation of exact values of very large m ...