bzoj3230 相似子串

题目链接

每个子串都是一个后缀的前缀

每个后缀贡献的子串数目是len-sa[i]-height[i];

因此可以二分找到一个子串的位置,要求某两个子串的最长公共前缀和最长公共后缀,把原串倒过再来一发就好,然后st表O(1)查询;

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<string>
  7 #include<cmath>
  8 #include<ctime>
  9 #include<queue>
 10 #include<stack>
 11 #include<map>
 12 #include<set>
 13 #define rre(i,r,l) for(int i=(r);i>=(l);i--)
 14 #define re(i,l,r) for(int i=(l);i<=(r);i++)
 15 #define Clear(a,b) memset(a,b,sizeof(a))
 16 #define inout(x) printf("%d",(x))
 17 #define douin(x) scanf("%lf",&x)
 18 #define strin(x) scanf("%s",(x))
 19 #define LLin(x) scanf("%lld",&x)
 20 #define op operator
 21 #define CSC main
 22 typedef unsigned long long ULL;
 23 typedef const int cint;
 24 typedef long long LL;
 25 using namespace std;
 26 void inin(int &ret)
 27 {
 28     ret=0;int f=0;char ch=getchar();
 29     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=getchar();}
 30     while(ch>=‘0‘&&ch<=‘9‘)ret*=10,ret+=ch-‘0‘,ch=getchar();
 31     ret=f?-ret:ret;
 32 }
 33 char s[100010];
 34 int LOG[100010],n,q;
 35 cint inf=2147483647;
 36 struct string
 37 {
 38     int sa[100010],h[100010],t[100010],t2[100010],c[100010],rank[100010];
 39     LL sum[100010];
 40     int f[100010][20];
 41     void build_sa(int m)
 42     {
 43         int *x=t,*y=t2;
 44         re(i,0,m-1)c[i]=0;
 45         re(i,0,n-1)x[i]=s[i],c[x[i]]++;
 46         re(i,1,m-1)c[i]+=c[i-1];
 47         rre(i,n-1,0)sa[--c[x[i]]]=i;
 48         for(int k=1;k<=n;k<<=1)
 49         {
 50             int p=0;
 51             rre(i,n-1,n-k)y[p++]=i;
 52             re(i,0,n-1)if(sa[i]>=k)y[p++]=sa[i]-k;
 53             re(i,0,m-1)c[i]=0;
 54             re(i,0,n-1)c[x[y[i]]]++;
 55             re(i,1,m-1)c[i]+=c[i-1];
 56             rre(i,n-1,0)sa[--c[x[y[i]]]]=y[i];
 57             swap(x,y);
 58             x[sa[0]]=0;p=1;
 59             re(i,1,n-1)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
 60             if(p>=n)return ;
 61             m=p;
 62         }
 63     }
 64     void build_height()//
 65     {
 66         int k=0;
 67         re(i,0,n-1)rank[sa[i]]=i;
 68         re(i,0,n-1)
 69         {
 70             if(k)k--;
 71             if(!rank[i])continue ;
 72             int j=sa[rank[i]-1];
 73             while(s[i+k]==s[j+k])k++;
 74             h[rank[i]]=k;
 75         }
 76     }
 77     void build_sum()//
 78     {
 79         sum[0]=n-sa[0];
 80         re(i,1,n-1)sum[i]=sum[i-1]+n-h[i]-sa[i];
 81     }
 82     void build_RMQ()//
 83     {
 84         re(i,1,n-1)f[i][0]=h[i];
 85         for(int j=1;(1<<j)<n;j++)
 86             for(int i=1;i+(1<<(j-1))<n;i++)
 87                 f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
 88     }
 89     void init()
 90     {
 91         build_sa(256);
 92         build_height();
 93         build_sum();
 94         build_RMQ();
 95     }
 96     void find(LL wei,int &a,int &b)//
 97     {
 98         int x=lower_bound(sum,sum+n,wei)-sum;
 99         a=sa[x],b=sa[x]+h[x]+wei-(x?sum[x-1]:0);
100     }
101     int query(int l,int r)//
102     {
103         l=rank[l],r=rank[r];
104         if(r<l)swap(l,r);l++;
105         int k=LOG[r-l+1];
106         return min(f[l][k],f[r-(1<<k)+1][k]);
107     }
108 }A,B;
109 int main()
110 {
111     freopen("in.in","r",stdin);
112     freopen("out.out","w",stdout);
113     inin(n),inin(q);
114     LOG[0]=-1;
115     re(i,1,100000)LOG[i]=LOG[i>>1]+1;
116     strin(s);
117     A.init();
118     reverse(s,s+n);
119     B.init();
120     while(q--)
121     {
122         int a1,b1,a2,b2,t;
123         LL l,r,ans=0;
124         LLin(l),LLin(r);
125         if(l>A.sum[n-1]||r>A.sum[n-1])
126         {
127             cout<<"-1\n";
128             continue;
129         }
130         A.find(l,a1,b1);
131         A.find(r,a2,b2);
132         t=a1==a2?inf:A.query(a1,a2);
133         t=min(t,min(b1-a1,b2-a2));
134         ans+=(LL)t*t;
135         t=b1==b2?inf:B.query(n-b1,n-b2);
136         t=min(t,min(b1-a1,b2-a2));
137         ans+=(LL)t*t;
138         printf("%lld\n",ans);
139     }
140      return 0;
141 }
时间: 2024-10-10 13:42:03

bzoj3230 相似子串的相关文章

BZOJ3230 相似子串 【后缀数组】

题目链接 BZOJ3230 权限题 题解 后缀数组基础题 询问第K大不同子串和正反lcp长度 如果您RE了,您就要知道询问的输入会爆LL #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define Redge(u) for (int k = h[u],to; k; k =

目前的字符串

Aho-Corasick automaton:BZOJ4820[bzoj2754][SCOI2012]喵星球上的点名后缀数组:BZOJ4310 跳蚤manacher: BZOJ3160万径人踪灭Palindromic Tree:bzoj4044Bzoj3676:[Apio2014]回文串 bzoj 1559 ** ac+jvchengBZOJ1195:[HNOI2006]最短母串 ** ac+jvchengbzoj 1692 * sabzoj 1031 * sabzoj 3796 ** sa+k

字符串题表

已完成bzoj1559 ** ac+jvchengbzoj1195:[HNOI2006]最短母串 ** ac+jvchengbzoj1692 * sabzoj1031 * sabzoj3796 ** sa+kmpbzoj3230:相似子串 ** sa+stbzoj4698 *** sabzoj2160:拉拉队排练 * manacherbzoj3790 * manacher+tanxinbzoj2565:最长双回文串 * manacher+luangaobzoj1414:[ZJOI2009]对称的

后缀数组(无讲解)

BZO2754: [SCOI2012]喵星球上的点名 题目链接 分析: 把姓和名中间用一个分隔符分开,和询问串一起建立后缀数组. 后缀数组上每个位置存对应串的标号.对于一个询问串(T),找到他对应的位置. 考虑和他的lcp>=len(T)的位置都是合法的.左右二分/倍增提取出这样的区间. 那么第一问转化成了区间颜色数量.树状数组即可. 第二问相当于有若干次区间 只在第一次出现的位置 加.然后查询每个位置的和.方法类似,不过这次我们扫一遍序列. 假设当前位置为i.先加入左端点是i的询问,在i处+1

LeetCode 30 Substring with Concatenation of All Words(与所有文字串联子串)(*)

翻译 给定一个字符串S,一个单词的列表words,全是相同的长度. 找到的子串(多个)以s即每个词的字串联恰好一次并没有任何插入的字符所有的起始索引. 原文 You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word

最长公共子串

(连续) - 阿里笔试[分析+编码] 题目描述:给定一个query和一个text,均由小写字母组成.要求在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度.例如,query为“acbac”,text为“acaccbabb”,那么text中的“cba”为最长的连续出现在query中的字母序列,因此,返回结果应该为其长度3.请注意程序效率. [思路]用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0.然后求出对角线最长的1序列,其对应的位置

HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

Problem Description Now you are back,and have a task to do: Given you a string s consist of lower-case English letters only,denote f(s) as the number of distinct sub-string of s. And you have some query,each time you should calculate f(s[l...r]), s[l

c之PAT刷题---删除字符串中的特定子串

改了好久还是没有全过,等明天再看吧!好好休息,明天继续. #include<stdio.h> #include<string.h> char *delete(char str1[80],char str2[80]){ int len1,len2,l;//l记录出现字符相同的起始位置 len1=strlen(str1); len2=strlen(str2); for(int i=0;str1[i]!='\0';i++){ if(str1[i]==str2[0]){ l=i;//记下相

寻找最大子串

题目:从一个数组中寻找一个连续子数组,使其中元素之和最大,给出该和值. 例如:数组[-2, 1, -3, 4, -1, 2, 1, -5, 4]和最大的子串是[4, -1, 2, 1],其和为6. 分析: 将数组从中间切分,中间元素属于左边,则最大子串为下面三种情况之一: 子串仅包含左边元素: 子串仅包含右边元素: 子串同时包含左边和右边的元素: 代码: // JavaScript solution function findMaxSubArray(a, begin, end) {   if(b