题意:有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. sharepoint 删除list里的所有内容

    [System.reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") $siteUrl = " ...

  2. PHP JQuery Json

    PHP: echo Json_encode($result); Jquery: $.get( 'process.php', {'p1':'aa','p2':'dd', 'data_type':'jso ...

  3. unity3d环境安装指南: Unity 4.5.5 + Visual Studio 2010

    1. UnitySetup-4.5.5.exe 官网下载最新版本4.X 安装exe文件 2. Unity 4.x Pro Patch.exe 复制exe到安装目录下 C:\Program Files ...

  4. wpf ListBox或ListView等数据控件 绑定数据,最简单的方式

    在网上很难找最简单的案例,都是一大片,看着都头疼: 试试举一反三,如果把结果赋给DataContext这个属性,那就前台需要绑定ItemsSource="{Binding}",请注 ...

  5. (poj)1064 Cable master 二分+精度

    题目链接:http://poj.org/problem?id=1064 Description Inhabitants of the Wonderland have decided to hold a ...

  6. 在Mac OS X中使用VIM开发STM32(2)

    本文原创于http://www.cnblogs.com/humaoxiao,非法转载者请自重! 在我先前的博文⎣在Mac OS X中使用VIM开发STM32(1)⎤中,我们安装完成了MACVIM,这一 ...

  7. AngularJS(1)随笔

    ng-app 指令告诉 AngularJS,<div> 元素是 AngularJS 应用程序 的"所有者". ng-model 指令把输入域的值绑定到应用程序变量 na ...

  8. platform_driver_register()--如何match之后调用probe

    int platform_driver_register(struct platform_driver *drv) { drv->driver.bus = &platform_bus_t ...

  9. Oracle数据库插入图片和读取图片

    package com.basicSql.scroll_page; import java.io.File; import java.io.FileInputStream; import java.i ...

  10. Hive 自定义函数(转)

    Hive是一种构建在Hadoop上的数据仓库,Hive把SQL查询转换为一系列在Hadoop集群中运行的MapReduce作业,是MapReduce更高层次的抽象,不用编写具体的MapReduce方法 ...