点击打开链接

题目大意:通常押韵的两个词以相同的字符结尾。我们运用这个特性来规定反押韵的概念。反押韵是一对拥有近似开头的单词。一对单词的反押韵的复杂度被定义为两者都以之开头且最长的字符串S的长度。因此,"arboreal" 和"arturus"是复杂度为2的一对反押韵,且"chalkboard"和"overboard"是一对复杂度为0的反押韵。你将得到一列单词。你的任务是,得到一列(i,j)形式的问题后,输出列表上以第i个和第j个组成的一对字符串的反押韵的复杂度。

字符串个数与询问的个数还有字符串的长度都在输入中说明。有字符串的长度*询问的数量得到最坏情况下一个case的复杂度为O(L*Q). 其中L和Q的数据范围确定了暴力肯定会超时!

然后后缀数组的性质可以通过后缀数组确定最长公共前缀(LCP)的长度。利用倍增法求后缀数组只需要O(nlogn)的时间复杂度。然后每次确定两个串之间LCP只需要求以两个目标串为钱缀的后缀之间求height的最小值即可。但是如果每次求最小值都需要O(N)的复杂度任然会超时。可以利用RMQ算法先用O(nlogn)的复杂度预先处理下height数组。再利用RMQ的O(1)的复杂度求区间最值即可。 该题给n个字符串,我们可以将n个字符串拼接成一个长串求后缀数组后即可利用后缀数组确定height数组。然后便是RMQ问题。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;const int maxn = 4000010;
const int maxlog = 23;
struct SuffixArray
{int s[maxn];      // 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)int sa[maxn];     // 后缀数组int rank[maxn];   // 名次数组. rank[0]一定是n-1,即最后一个字符,rank从0开始int height[maxn]; // height数组 代表sa[i-1] 和 sa[i]的LCP的长度int t[maxn], t2[maxn], c[maxn]; // 辅助数组int n; // 字符个数void clear(){n = 0;memset(sa, 0, sizeof(sa));}// m为最大字符值加1。调用之前需设置好s和nvoid build_sa(int m){int i, *x = t, *y = t2;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[i] = s[i]]++;for(i = 1; i < m; i++) c[i] += c[i-1];for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;for(int k = 1; k <= n; k <<= 1){int p = 0;for(i = n-k; i < n; i++) y[p++] = i;for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[y[i]]]++;for(i = 0; i < m; i++) c[i] += c[i-1];for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];swap(x, y);p = 1;x[sa[0]] = 0;for(i = 1; i < n; i++)x[sa[i]] = y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k] ? p-1 : p++;if(p >= n) break;m = p;}}void build_height(){int i, j, k = 0;for(i = 0; i < n; i++) rank[sa[i]] = i;for(i = 1; i < n; i++){if(k) k--;int j = sa[rank[i]-1];while(s[i+k] == s[j+k]) k++;height[rank[i]] = k;}}
};
struct RMQ //用于求区间最值
{int d[maxn][maxlog];void init(const int * A, int n) //被求最值的数组,数组的大小{//int n = A.size();for(int i = 0; i < n; i++)d[i][0] = A[i];for(int j = 1; (1<<j) <= n; j++)for(int i = 0; i + (1<<j) - 1 < n; i++)d[i][j] = min(d[i][j-1], d[i + (1<<(j-1))][j-1]);}int query(int L, int R){if(R < L) swap(L, R);L++;int k = 0;while((1<<(k+1)) <= R-L+1) k++; // 如果2^(k+1)<=R-L+1,那么k还可以加1return min(d[L][k], d[R-(1<<k)+1][k]);}
};
RMQ rmq;SuffixArray sa;
int pos[maxn], len[maxn];
char t[maxn];
int main()
{//freopen("cin.txt","r",stdin);int T,ca=1,n,m;scanf("%d\n",&T);while(T--){printf("Case %d:\n",ca++ );scanf("%d",&n);int u=1;for(int i=1;i<=n;i++){scanf("%s",t);len[i]=strlen(t);pos[i]=u; //每个字符串开头的位置for(int j=0;j<len[i];j++) sa.s[u++]=t[j];}sa.s[u]=0;sa.n=u;sa.build_sa(256); //ascii码最大值为255sa.build_height();rmq.init(sa.height,u);scanf("%d",&m);int x,y;int ans;for(int i=0;i<m;i++){scanf("%d%d",&x,&y);ans=min(len[x],len[y]);if(x==y)printf("%d\n",ans);else{ans=min(ans,rmq.query(sa.rank[pos[x]],sa.rank[pos[y]]));printf("%d\n",ans);}}}
}

rmq算法模板 o(n*log(n)) 预处理 o(1)查询

struct RMQ //用于求区间最值
{int d[maxn][maxlog];void init(const int * A, int n) //被求最值的数组,数组的大小{//int n = A.size();for(int i = 0; i < n; i++)d[i][0] = A[i];for(int j = 1; (1<<j) <= n; j++)for(int i = 0; i + (1<<j) - 1 < n; i++)d[i][j] = max(d[i][j-1], d[i + (1<<(j-1))][j-1]);//最小值改为min}int query(int L, int R){if(R < L) swap(L, R);//L++;              //根据rank数组下标而定,该题rank[0]=n-1,是自己设的表示末尾的字符int k = 0;while((1<<(k+1)) <= R-L+1) k++; return max(d[L][k], d[R-(1<<k)+1][k]);//最小值改为min}
};
RMQ rmq;

后缀数组算法模板o(n*logn)

struct SuffixArray
{int s[maxn];      // 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)int sa[maxn];     // 后缀数组(从第i个字符开始的字符串是第几名)int rank[maxn];   // 名次数组. rank[0]一定是n-1,即最后一个字符,rank从0开始int height[maxn]; // height数组 代表sa[i-1] 和 sa[i]的LCP的长度int t[maxn], t2[maxn], c[maxn]; // 辅助数组int n; // 字符个数void clear(){n = 0;memset(sa, 0, sizeof(sa));}// m为最大字符值加1。调用之前需设置好s和nvoid build_sa(int m){int i, *x = t, *y = t2;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[i] = s[i]]++;for(i = 1; i < m; i++) c[i] += c[i-1];for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;for(int k = 1; k <= n; k <<= 1){int p = 0;for(i = n-k; i < n; i++) y[p++] = i;for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[y[i]]]++;for(i = 0; i < m; i++) c[i] += c[i-1];for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];swap(x, y);p = 1;x[sa[0]] = 0;for(i = 1; i < n; i++)x[sa[i]] = y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k] ? p-1 : p++;if(p >= n) break;m = p;}}void build_height()//建立height数组,用于求排名相邻的两个后缀的最长公共前缀{int i, j, k = 0;for(i = 0; i < n; i++) rank[sa[i]] = i;for(i = 1; i < n; i++){if(k) k--;int j = sa[rank[i]-1];while(s[i+k] == s[j+k]) k++;height[rank[i]] = k;}}
};

F - Anti-Rhyme Pairs(rmq算法模板)(后缀数组算法模板)相关推荐

  1. 算法笔记——后缀数组

    后缀指从某个位置开始到字符串末尾的一个子串,用suffix(i)来表示. 后缀数组(suffix array)指将s的所有后缀从小到大排序后,取其下标i放入数组中,该数组就叫做后缀数组. 表示排名为i ...

  2. 试题 算法训练 后缀数组——最长重复子串

    资源限制 时间限制:100ms 内存限制:256.0MB 问题描述 给定一个长度为n的数串,求至少出现k 次的最长重复子串的长度,这k 个子串可以重叠.保证有子串出现至少k次. 输入格式 第一行:两个 ...

  3. 【后缀数组】洛谷P3809模板题

    题目背景 这是一道模板题. 题目描述 读入一个长度为 n n n 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置. ...

  4. 后缀数组 相关问题模板

    后缀数组函数模板: const int MAX=200020; int wa[MAX],wb[MAX],wsf[MAX],wv[MAX],sa[MAX]; int rank[MAX],height[M ...

  5. 后缀数组(未完待续)

    后缀数组 简介 后缀数组(Suffix Array, SA)是一种在字符串问题中很实用的工具,其主要作用是求多模板匹配和最长公共前缀(LCP).与 AC自动机 预先处理模板串不同,后缀数组在进行多模板 ...

  6. poj 3693 后缀数组

    链接:点我 1 /* 2 * POJ 3693 Maximum repetition substring 3 * 先穷举长度L,然后求长度为L的子串最多能连续出现多少次 4 * 既然长度为L的串重复出 ...

  7. 使用增强型后缀数组(ESA)的文本匹配算法

    设模式串的长度为m,文本的长度为n,使用后缀数组做文本匹配,如果只用后缀表suftab和折半查找算法的复杂度为O(m*logn): 如果使用最长公共前缀表lcptab和折半查找算法,复杂度可以降至O( ...

  8. 后缀树和后缀数组的一些资料收集

    后缀树(Suffix tree)是一种数据结构,能快速解决很多关于字符串的问题.后缀树的概念最早由Weiner 于1973年提出,既而由McCreight 在1976年和Ukkonen在1992年和1 ...

  9. POJ - 3261 Milk Patterns(二分+后缀数组)

    题目链接:点击查看 题目大意:给出一个字符串,以及一个k,现在求出现次数大于等于k次的最大可重叠子串的长度 题目分析:可以说是后缀数组的模板题目了吧..直接跑出height数组,因为height数组代 ...

最新文章

  1. python高频面试题_2019下半年金九银十Python高频面试题(第四弹)
  2. python培训班那家好-python培训班那个好?
  3. 关于Git你必须知道的
  4. 2017年11月1号复习
  5. 使用Aspose.Cells组件生成Excel文件实例
  6. vsphere虚拟克隆虚拟服务器,vSphere实战攻略2:虚拟机模板与克隆
  7. 2013年。。。。。。
  8. oracle对象权限 函数,oracle的系统和对象权限
  9. Linux系统特点介绍集合
  10. asp.net oracle连接数据库,ASP.NET连接Oracle数据库的步骤详解
  11. 拔掉机器人的一条腿,它还能学走路?| 三次元里优化的DRL策略
  12. vs点击方法跳不到对于的地方_迷你世界:大神玩花式跑酷有多简单?老玩家教你,轻松学会百段跳...
  13. Gradle Groovy 基础语法 MD
  14. android内存泄漏原因分析,Android 内存泄漏案例分析总结(Handler)
  15. cloudflare 关于tls 检测,发送未知message type字节
  16. linux中c表示字符设备文件符号
  17. ssh 远程连接详解--(linux运维09)
  18. 中兴捧月算法挑战赛-RAW夜景图像去噪总结
  19. C++ | isupper函数用法
  20. 小程序列表页制作优惠券效果

热门文章

  1. 动态规划——数字三角形C语言
  2. 搜索功能(支持全拼,首字母,不区分大小写,关键字变色等)
  3. 【电源模块】ME3116 DCDC降压模块设计
  4. Printf函数基本概念
  5. 人以善感,天以福应,人以恶感,天以灾应,原来天就是自己的镜子呀!
  6. SEO教程VIP资源合集,速度领!手慢无
  7. SRPG游戏开发(一)前言
  8. 使用html+css+js实现一个静态页面(含源码)
  9. Django之爱鲜蜂项目开发 day05(一)
  10. 复旦计算机学院套磁,从北大信科到MITEECSPhD,我的2018申请总结!