题意:有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. Html5时钟的实现

    最近准备把自己的博客装修一下,首先,先为自己设计一个时钟吧,希望博客园能够尽快发放给我使用js的权限! 自从看见了苹果设计的那款因为侵权而赔钱了时钟,我就决定我的时钟一定是要参考这个来设计了! 不得不 ...

  2. 20150503-struts2入门-标签

    一.几个标签介绍 1.property标签 property标签用于输出指定值: <s:set name="name" value="'kk'" /> ...

  3. jsp页面在IE8下文本模式自动为“杂项(Quirks)”导致页面显示错位

    最近在修改网站的响应式的页面时,由于都是套样式页面,修改过程都是粘贴复制,导致了一些细节问题在IE8下暴露出来: 遇到的问题就是在在Chrome,火狐页面都正常,唯独在IE8下页面样式显示乱样了,但是 ...

  4. Objective-C 【继承、变量修饰符(私有变量/方法)、description方法】

    ------------------------------------------- 继承 一段代码: #import <Foundation/Foundation.h> @interf ...

  5. CSS3几个速记标签2

    @font-face:CSS3允许使用自己的字体,用户会自动下载     语法:@font-face{font-family:---:src:url(---)}     如果要使用粗体,必须新添加另一 ...

  6. MySql事务及JDBC对事务的使用

    一 .事务的几个重要特性 1. 原子性 事务内的每个内容不可分割,是一个统一的整体.或同时进行或同时消亡. 2.一致性 事务执行前和事务执行后,状态都是统一的.如A转B 100元,A和B数据总额度没有 ...

  7. hdu 1715 大菲波数(高精度数)

    Problem Description Fibonacci数列,定义如下: f(1)=f(2)=1 f(n)=f(n-1)+f(n-2) n>=3. 计算第n项Fibonacci数值. Inpu ...

  8. A Case Study -- Performance Evaluation of a DRAM-Based Solid State Disk

    研究将固态硬盘作为持久存储层和传统硬盘的在数据库性能上的研究

  9. Project not selected to build for this solution configuration.

    Project not selected to build for this solution configuration.   When you upgrade your older solutio ...

  10. hdu 5646 DZY Loves Partition 二分+数学分析+递推

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5646 题意:将n分成k个正整数之和,要求k个数全部相同:并且这k个数的乘积最大为多少?结果mod 1e^9 ...