51nod 1732 51nod婚姻介绍所 后缀数组:最长公共前缀

2023-11-09 23:48

本文主要是介绍51nod 1732 51nod婚姻介绍所 后缀数组:最长公共前缀,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1732 51nod婚姻介绍所

  1. 1.0 秒
  2.  
  3. 131,072.0 KB
  4.  
  5. 40 分
  6.  
  7. 4级题

51nod除了在做OJ之外,还开展了很多副业。婚姻介绍所就是其中之一。

对于一个客户,我们可以使用一个字符串来描述该客户的特质。

假设现在我们有两个客户A和B。

A的特质字符串为:abcdefg

B的特质字符串为:abcxyz

则A和B的匹配度f(A, B)为A和B的最长公共前缀的长度,即len('abc') = 3

由于最近51nod经费紧张,所以夹克大老爷设计了一种压缩算法以节约内存。

所有用户的特质字符串都被存储在了一个长为n的字符串S中。(n <= 1000)用户的特质使用一个整数p表示,表示该用户的特质字符串为S[p...n - 1]。

现给定字符串S,与q次查询<ai, bi>(ai, bi分别为合法的用户特质整数)。请输出q次查询分别对应的客户匹配度。

 

 收起

输入

现给定字符串长度n,与字符串S。接下来是整数q,代表接下来有q次查询。
下面q行有两个整数ai, bi。代表查询特质为ai与bi的用户的匹配度。1 <= n <= 1000
1 <= q <= 10^6输入数据全部合法。

输出

每一行输出一个用户匹配度整数。

输入样例

12
loveornolove
5
3 7
0 0
9 1
3 1
9 5

输出样例

0
12
3
0
0

 

分析:

后缀数组的模板题,注意快读

#include <bits/stdc++.h>
using namespace std;
const int maxn=200000+1000;
int len1,len2;
void in(int &x)
{x=0;char c=getchar();while(c<'0'||c>'9'){c=getchar();}x=c-'0';while(c=getchar()){if(c<'0'||c>'9') break;x=x*10+c-'0';}
}void out(int x)
{if(x>=10)out(x/10);putchar(x%10+'0');
}
struct SuffixArray
{char s[maxn];///_rank[i] 第i个后缀的排名; SA[i] 排名为i的后缀位置; Height[i] 排名为i的后缀与排名为(i-1)的后缀的LCPint sa[maxn],_rank[maxn],height[maxn];///c[i] 基数排序辅助数组int t1[maxn],t2[maxn],c[maxn],n;int dmin[maxn][21];void init(){memset(height,0,sizeof(height));memset(_rank,0,sizeof(_rank));memset(sa,0,sizeof(sa));memset(c,0,sizeof(c));memset(t1,0,sizeof(t1));memset(t2,0,sizeof(t2));memset(dmin,0,sizeof(dmin));}void build_sa(int m)  ///m大于s[]数组出现的任意字符的int值{/// x[i]是第i个元素的第一关键字  y[i]表示第二关键字排名为i的数,第一关键字的位置int i,p,*x=t1,*y=t2;x[n]=y[n]=-1;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){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[i]]++;for(i=1; 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++){if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])x[sa[i]]=p-1;elsex[sa[i]]=p++;}if(p>=n)break;m=p;}}void build_height()//单个字符也行{int i,j,k=0,r;for(i=0; i<n; i++)_rank[sa[i]]=i;height[0]=0;for(i=0; i<n; i++){if(k)k--;r=_rank[i];if(r==0)continue;j=sa[r-1];while(s[i+k]==s[j+k])k++;height[_rank[i]]=k;}}int LongestMessage() //最长公共子串{int ans=0;for(int i=2; i<n; i++){int a1=sa[i-1],a2=sa[i];if(a1>a2)swap(a1,a2);if(a1>=0&&a1<=len1-1&&a2>=len1+1&&a2<=len1+len2)ans = max(ans,height[i]);}return ans;}void initMin(){for(int i=0; i<n; i++)dmin[i][0]=height[i];for(int j=1; (1<<j)<=n; j++)for(int i=0; i+(1<<j)-1<n; i++)dmin[i][j]=min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);}int RMQ(int L,int R)//取得范围最小值{int k=0;while((1<<(k+1))<=R-L+1)k++;return min(dmin[L][k], dmin[R-(1<<k)+1][k]);}int LCP(int i,int j)//求后缀i和j的LCP最长公共前缀{if(i==j) return n-i;int L=_rank[i],R=_rank[j];//求后缀i与后缀j的LCP//if(i==j) return n-sa[i];//int L=i,R=j;//直接求排名i与j后缀的LCPif(L>R)swap(L,R);L++;//注意这里return RMQ(L,R);}int num()//子串的个数{int ans=0;for(int i=1; i<n; i++)ans += n-1-sa[i]-height[i];return ans;}//确定子串[be,be+len-1]的在后缀排名区间[L,R]int get_LR(int be,int len,int &L,int &R){int pos=_rank[be];int l=0,r=pos;while(l<r){int mid=(l+r)>>1;if(RMQ(mid+1,pos)>=len)r=mid;elsel=mid+1;}L=l;l=pos;r=n-1;while(l<r){int mid=(l+r+1)>>1;if(RMQ(pos+1,mid)>=len)l=mid;elser=mid-1;}R=l;}//恰好出现w次子串的个数int num_w(int w){int ans=0;for(int i=0; i+w-1<n; i++)ans+=max(0,LCP(i,i+w-1)-max(height[i],height[i+w]));return ans;}void out(){for(int i=0; i<n; i++){cout<<sa[i]<<" ";}cout<<endl;for(int i=0; i<n; i++){cout<<_rank[i]<<" ";}cout<<endl;for(int i=0; i<n; i++){cout<<height[i]<<" ";}cout<<endl;}
} sa;
int main()
{sa.init();scanf("%d",&len1);scanf("%s",sa.s);sa.n=len1;sa.build_sa(256);sa.build_height();sa.initMin();int q;in(q);int a,b;while(q--){in(a);in(b);if(a==b)out(len1-a);elseout(sa.LCP(a,b));puts("");}return 0;
}

 

 

这篇关于51nod 1732 51nod婚姻介绍所 后缀数组:最长公共前缀的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/379172

相关文章

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

JAVA数组中五种常见排序方法整理汇总

《JAVA数组中五种常见排序方法整理汇总》本文给大家分享五种常用的Java数组排序方法整理,每种方法结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录前言:法一:Arrays.sort()法二:冒泡排序法三:选择排序法四:反转排序法五:直接插入排序前言:几种常用的Java数组排序

正则表达式r前缀使用指南及如何避免常见错误

《正则表达式r前缀使用指南及如何避免常见错误》正则表达式是处理字符串的强大工具,但它常常伴随着转义字符的复杂性,本文将简洁地讲解r的作用、基本原理,以及如何在实际代码中避免常见错误,感兴趣的朋友一... 目录1. 字符串的双重翻译困境2. 为什么需要 r?3. 常见错误和正确用法4. Unicode 转换的

Java如何根据文件名前缀自动分组图片文件

《Java如何根据文件名前缀自动分组图片文件》一大堆文件(比如图片)堆在一个目录下,它们的命名规则遵循一定的格式,混在一起很难管理,所以本文小编就和大家介绍一下如何使用Java根据文件名前缀自动分组图... 目录需求背景分析思路实现代码输出结果知识扩展需求一大堆文件(比如图片)堆在一个目录下,它们的命名规

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

SpringBoot自定义注解如何解决公共字段填充问题

《SpringBoot自定义注解如何解决公共字段填充问题》本文介绍了在系统开发中,如何使用AOP切面编程实现公共字段自动填充的功能,从而简化代码,通过自定义注解和切面类,可以统一处理创建时间和修改时间... 目录1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3