字符串(后缀数组):HAOI2016 找相同子串

[HAOI2016]找相同子串

【题目描述】

给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。

【输入格式】

两行,两个字符串s1,s2,长度分别为n1,n2。

【输出格式】

输出一个整数表示答案。

【样例输入】

aabb
bbaa

【样例输出】

10

【数据范围】

对于20%的数据,满足1≤n1,n2≤500;

对于40%的数据,满足1≤n1,n2≤5000;

对于100%的数据,满足1≤n1,n2≤200000,字符串中只有小写字母。

  和POJ 3415几乎一样。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int N=400010;
 6 char s[N];int len,d;
 7 int r[N],Wa[N],Wb[N],sa[N],rk[N];
 8 int Ws[N],Wv[N],lcp[N];
 9
10 bool cmp(int *p,int i,int j,int l){
11     return p[i]==p[j]&&p[i+l]==p[j+l];
12 }
13
14 void DA(int n,int m){
15     int i,j,p,*x=Wa,*y=Wb;
16     for(i=0;i<m;i++)Ws[i]=0;
17     for(i=0;i<n;i++)++Ws[x[i]=r[i]];
18     for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
19     for(i=n-1;i>=0;i--)sa[--Ws[x[i]]]=i;
20     for(j=1,p=1;p<n;j<<=1,m=p){
21         for(p=0,i=n-j;i<n;i++)y[p++]=i;
22         for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
23         for(i=0;i<m;i++)Ws[i]=0;
24         for(i=0;i<n;i++)++Ws[Wv[i]=x[y[i]]];
25         for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
26         for(i=n-1;i>=0;i--)sa[--Ws[Wv[i]]]=y[i];
27         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++)
28             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
29     }
30 }
31
32 void LCP(int n){
33     int i,j,k=0;
34     for(i=1;i<=n;i++)rk[sa[i]]=i;
35     for(i=0;i<n;lcp[rk[i++]]=k)
36         for(k?k--:k,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
37 }
38
39 int ID(int x){x=sa[x];
40     if(x==d)return 0;
41     if(x<d)return 1;
42     return 2;
43 }
44
45 int st[N]={-1},top;
46 long long sum[N],tot[N],ans;
47 int main(){
48     freopen("find_2016.in","r",stdin);
49     freopen("find_2016.out","w",stdout);
50     scanf("%s",s);
51     len=d=strlen(s);
52     scanf("%s",s+len+1);
53     s[d]=‘#‘;len=strlen(s);
54     for(int i=0;i<len;i++)r[i]=s[i];
55     DA(len+1,128);LCP(len);
56     for(int i=1;i<=len;i++){
57         if(!ID(i))continue;
58         if(ID(i)==2)ans+=tot[top];
59         if(i!=len){
60             st[++top]=lcp[i+1];sum[top]=2-ID(i);
61             tot[top]=st[top]*sum[top]+tot[top-1];
62             while(st[top]<=st[top-1]){
63                 sum[top-1]+=sum[top];
64                 st[top-1]=st[top];top--;
65                 tot[top]=st[top]*sum[top]+tot[top-1];
66             }
67         }
68     }
69     top=0;
70     for(int i=1;i<=len;i++){
71         if(!ID(i))continue;
72         if(ID(i)==1)ans+=tot[top];
73         if(i!=len){
74             st[++top]=lcp[i+1];sum[top]=ID(i)-1;
75             tot[top]=st[top]*sum[top]+tot[top-1];
76             while(st[top]<=st[top-1]){
77                 sum[top-1]+=sum[top];
78                 st[top-1]=st[top];top--;
79                 tot[top]=st[top]*sum[top]+tot[top-1];
80             }
81         }
82     }
83     printf("%lld\n",ans);
84     return 0;
85 }
时间: 2025-01-06 11:16:08

字符串(后缀数组):HAOI2016 找相同子串的相关文章

SPOJ 694、705 后缀数组:求不同子串

思路:这题和wikioi 1306一样,也都是求的不同子串的个数,但是wikioi 时间比较长,然后用Trie树就过了.但是我用那个代码提交这题的时候就WA了,比较晕--因为这题有多组样例,所以超了点时间. 所以这题当然就是用后缀数组做的啦! 算法分析: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照suffix(sa[1]),suffix(sa[2]),suffix(sa[3]),--,suffix(sa[n])的顺序计算,不难发现,对于每

【hiho】120 后缀数组一&#183;重复旋律2【字符串--后缀数组--最长不可重叠重复子串问题】

传送门:后缀数组一·重复旋律2 题意 最长可重叠重复子串问题 思路 二分答案,转化成判定问题. 看看能不能找出不重叠的重复子串.对于每一组,我们检查这些后缀对应的sa值(也就是后缀起点在原串中的位置i).如果max{sa} - min{sa} >= k,那么就说明我们能找出一组不重叠的重复子串 AC Code #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; c

面试题[后缀数组]: 最长重复子串

题目:给定一个字符串,求出最长重复子串. 这个题目可以用后缀数组来解:对后缀数组排好序,这样重复的子串就在相邻的后缀中找就可以了.我的C++代码实现如下: class Solution { public: string LongestRepeatingSubstring(string str) { size_t len = str.size(); vector<string> SuffixArray(len); for (size_t i = 0; i < len; ++i) Suffi

bzoj4556: [Tjoi2016&amp;Heoi2016]字符串 (后缀数组加主席树)

题目是给出一个字符串,每次询问一个区间[a,b]中所有的子串和另一个区间[c,d]的lcp最大值,首先求出后缀数组,对于lcp的最大值肯定是rank[c]的前驱和后继,但是对于这个题会出现问题,就是题目中有区间的限制. For example: 5 1 aaaab 1 2 3 5 对于这个样例,如果直接找到aab的前驱是 aaab,然后由于区间的原因答案是1,但是如果我们再往前找的话,找到aaaab,答案会变成2.那就出现了错误.考虑一下怎么做可以去除这种影响呢? 我们可以二分一下,首先对于[a

Bzoj4556: [Tjoi2016&amp;Heoi2016]字符串 后缀数组

4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 169  Solved: 87[Submit][Status][Discuss] Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE O,嫁给高富帅,走上人生巅峰.

[XSY 1516] 兔子的字符串 后缀数组

题意 给定一个字符串 $S$ . 按照某种方式, 将字符串 $S$ 化成不超过 $K$ 段 $S_1, S_2, ..., S_K$ . 每段 $S_i$ 有字典序最大的子串 $C_i$ . 最小化 $C_i$ 的最大值. $N \le 200000$ . 分析 通过后缀数组, 先二分后缀, 再二分长度, 实现二分所有的字符串. 判定则可以贪心取, 利用后缀数组的信息, 记录 v[i] 表示位置 i 不能与位置 v[i] 在同一段中. 实现 #include <cstdio> #include

POJ 2217 (后缀数组+最长公共子串)

题目链接: http://poj.org/problem?id=2217 题目大意: 求两个串的最长公共子串,注意子串是连续的,而子序列可以不连续. 解题思路: 有个炒鸡快的O(n)的Manacher算法.不过只能求裸的最长公共和回文子串. 后缀数组解法是这类问题的模板解法. 对于n个串的最长公共子串,这要把这些串连在一起,中间用"$"这类的特殊符号分隔一下. 先求后缀数组,再求最长公共前缀,取相邻两个且属于不同串的sa的最大LCP即可. 原理就是:这样把分属两个串的LCP都跑了一遍,

HDOJ 题目4416 Good Article Good sentence(后缀数组求a串子串在b串中不出现的种类数)

-每周六晚的BestCoder(有米!) Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2784    Accepted Submission(s): 785 Problem Description In middle school, teachers used to encour

字符串(后缀数组):POJ 3415 Common Substrings

Common Substrings Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|. Given two strings A, B and one integer K, we define S, a set of triples (i, j, k): S = {(i, j, k) | k≥K, A(i, k)=B(j, k)}. You are to give