HDU 4622 Reincarnation( 任意區間子串的長度, 字尾陣列+RMQ)
題目大意:給你一個字串,給你N次查詢,每次給你一個區間讓你求出這個區間裡面有多少子串。
解題思路:我們肯定要列舉位置,然後找公共子串然後再去掉重複的,但是他的地址對應的rank不是連續的,如果暴力找的話會n*n會超時。
從這個部落格學習到一種方法:首先對整個字串求一次sa[]以及height[],之後對於任意區間[L, R],遍歷一遍sa[],只要起點在[L, R]內的字尾就需要進行統計,類似於1)中的方法,不過有一個地方要特別注意的就是全部的sa[]不一定就是區間內的sa[],這是因為區間內的字尾比較時有額外的長度限制。可以證明遍歷的過程要遵循如下的規則:
字尾s1和字尾s2現在是兩個待比較的字尾,s1在前,s2在後,其起點都在區間[L, R]內,並設兩串在區間中的長度為 len1, len2, 其全域性的最長公共字首為 lcp。現考慮在遍歷sa[]時,如何從全域性sa[]得到正確的區域性sa[]:
1: lcp < len1 && lcp < len2 時說明兩個串在未結束時就比較出了大小,全域性和區域性的sa[]統一,因此可以放心令s2作為下一個字典序字尾;
2: lcp >= len1 && lcp >= len2 時說明在其中一個串結束時,兩個串對應字元都是相等的,這時需要根據len1和len2關係來決定,如果len1>len2那麼就不用更換了;
3: lcp >= len1 && lcp < len2 時說明在其中一個串結束時,兩個串對應字元都是相等的,由於s2的長度比s1長,因此字典序肯定大,因此需要更換當前的字尾;
4: lcp < len1 && lcp >= len2 時說明在其中一個串結束時,兩個串對應字元都是相等的,由於s1的長度比s2長,因此字典序肯定大,因此不需更換當前的字尾。
其中2和4條件可以合併,如果4成立,那麼必定有 len1 > len2,因此可以簡化這個判斷這個過程:if (len1 > len2 && lcp >= len2) 則不更換 else 更換。
if(la > lb && lcp >= lb){不交換} else {交換};
直接理解就是給結果帶來誤差的情況只會是某個被lcp完全包含的字尾被排在了後面,那麼它的正確位置應該是在最前面,由於在後面匹配的其長度仍未整個區域性字尾的長度,而在選擇下一個字典序字尾時遮蔽掉這個字尾即可。
Reincarnation
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 2277 Accepted Submission(s): 795
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...r] means the sub-string of s start from l end at r.
For each test cases,the first line contains a string s(1 <= length of s <= 2000).
Denote the length of s by n.
The second line contains an integer Q(1 <= Q <= 10000),denote the number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n), denote a query.
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <ctime>
#include <map>
#include <set>
#define eps 1e-9
///#define M 1000100
///#define LL __int64
#define LL long long
///#define INF 0x7ffffff
#define INF 0x3f3f3f3f
#define PI 3.1415926535898
#define zero(x) ((fabs(x)<eps)?0:x)
#define mod 1000000007
#define Read() freopen("autocomplete.in","r",stdin)
#define Write() freopen("autocomplete.out","w",stdout)
#define Cin() ios::sync_with_stdio(false)
using namespace std;
inline int read()
{
char ch;
bool flag = false;
int a = 0;
while(!((((ch = getchar()) >= '0') && (ch <= '9')) || (ch == '-')));
if(ch != '-')
{
a *= 10;
a += ch - '0';
}
else
{
flag = true;
}
while(((ch = getchar()) >= '0') && (ch <= '9'))
{
a *= 10;
a += ch - '0';
}
if(flag)
{
a = -a;
}
return a;
}
void write(int a)
{
if(a < 0)
{
putchar('-');
a = -a;
}
if(a >= 10)
{
write(a / 10);
}
putchar(a % 10 + '0');
}
const int maxn = 2050;
int wa[maxn], wb[maxn], wv[maxn], ws1[maxn];
int sa[maxn];
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int *r, int *sa, int n, int m)
{
int i, j, p, *x = wa, *y = wb;
for(i = 0; i < m; i++) ws1[i] = 0;
for(i = 0; i < n; i++) ws1[x[i] = r[i]]++;
for(i = 1; i < m; i++) ws1[i] += ws1[i-1];
for(i = n-1; i >= 0; i--) sa[--ws1[x[i]]] = i;
for(j = 1, p = 1; p < n; j <<= 1, m = p)
{
for(p = 0, i = n-j; i < n; i++) y[p++] = i;
for(i = 0; i < n; i++)
if(sa[i] >= j) y[p++] = sa[i]-j;
for(i = 0; i < n; i++) wv[i] = x[y[i]];
for(i = 0; i < m; i++) ws1[i] = 0;
for(i = 0; i < n; i++) ws1[wv[i]]++;
for(i = 1; i < m; i++) ws1[i] += ws1[i-1];
for(i = n-1; i >= 0; i--) sa[--ws1[wv[i]]] = y[i];
for(swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++;
}
}
int rank[maxn], height[maxn];
void calheight(int *r, int *sa, int n)
{
int i, j, k = 0;
for(i = 1; i <= n; i++) rank[sa[i]] = i;
for(int i = 0; i < n; height[rank[i++]] = k)
for(k?k--:0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
return ;
}
int dp[maxn][30];
void RMQ(int len)
{
for(int i = 1; i <= len; i++)
dp[i][0] = height[i];
for(int j = 1; 1<<j <= maxn; j++)
{
for(int i = 1; i+(1<<j)-1 <= len; i++)
dp[i][j] = min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
}
int lg[maxn];
int querry(int l, int r)
{
int k = lg[r-l+1];
return min(dp[l][k], dp[r-(1<<k)+1][k]);
}
void init()
{
lg[0] = -1;
for (int i = 1; i < maxn; ++i)
lg[i] = lg[i>>1] + 1;
}
char str[maxn];
int seq[maxn];
int Del(int l, int r, int n)
{
int ans = (r-l+2)*(r-l+1)/2;
int last = -1;
int k = r-l+1;
for(int i = 1; i <= n; i++)
{
if(!k) break;
if(sa[i] < l || sa[i] > r) continue;
k--;
if(last == -1)
{
last = i;
continue;
}
int a = last;
int b = i;
if(a > b) swap(a, b);
int lcp = querry(a+1, b);
int la = r-sa[last]+1;
int lb = r-sa[i]+1;
if(la > lb && lcp >= lb){}
else last = i;
ans -= min(lcp, min(la, lb));
}
return ans;
}
int main()
{
int T;
cin >>T;
init();
while(T--)
{
scanf("%s", str);
int len = strlen(str);
for(int i = 0; i < len; i++)
seq[i] = str[i]-'a'+1;
seq[len] = 0;
da(seq, sa, len+1, 27);
calheight(seq, sa, len);
RMQ(len);
int n;
int l, r;
scanf("%d",&n);
while(n--)
{
scanf("%d %d",&l, &r);
printf("%d\n", Del(l-1, r-1, len));
}
}
return 0;
}
相關文章
- POJ 2217-Secretary(字尾陣列+高度陣列-最大公共子串長度)陣列
- POJ 3294 Life Forms(字尾陣列求k個串的最長子串)ORM陣列
- POJ 2774-Long Long Message(字尾陣列+高度陣列-最大公共子串長度)陣列
- ural 1297 最長迴文子串 字尾陣列陣列
- HDU 5769-Substring(字尾陣列-不相同的子串的個數)陣列
- poj 2774 求兩字串的最長公共子串 字尾陣列字串陣列
- SPOJ 687. Repeats(字尾陣列求最長重複子串)陣列
- POJ 3415-Common Substrings(字尾陣列+單調棧-公共子串的長度)陣列
- POJ 3693 Maximum repetition substring(字尾陣列求最長重複子串)陣列
- POJ 1743 Musical Theme (字尾陣列,求最長不重疊重複子串)陣列
- SPOJ 220. Relevant Phrases of Annihilation(字尾陣列多次不重疊子串)陣列
- poj 3415 Common Substrings(長度大於k的相同子串對數xian 字尾陣列+單調桟統計)陣列
- 字尾陣列模板陣列
- 字尾陣列 SA陣列
- 字尾陣列,SA陣列
- SPOJ 694 求一個字串有多少子串 字尾陣列字串陣列
- 洛谷P3763 [TJOI2017]DNA(字尾陣列 RMQ)陣列MQ
- JavaScript 建立或填充任意長度陣列的小技巧JavaScript陣列
- 203. 長度最小的子陣列陣列
- 最長公共子串 二維陣列 Go實現陣列Go
- 字尾陣列複習陣列
- 字尾陣列(後續)陣列
- 字尾陣列詳解陣列
- 【筆記】字尾陣列筆記陣列
- URAL 1297. Palindrome(字尾陣列求最大回文串)陣列
- 【譯】在 JavaScript 中建立和填充任意長度的陣列JavaScript陣列
- HDU5147 Sequence II(樹狀陣列+字首和+字尾和)陣列
- DreamJudge-1294-字尾子串排序排序
- 每日一練(45):長度最小的子陣列陣列
- 繩子的長度;及找陣列的波谷分析陣列
- OI loves Algorithm——字尾陣列Go陣列
- 最長迴文子串(百度筆試題和hdu 3068)筆試
- 字元陣列的長度字元陣列
- 學習筆記----字尾陣列筆記陣列
- 字尾陣列 學習筆記陣列筆記
- 字尾陣列學習筆記陣列筆記
- 3254. 長度為 K 的子陣列的能量值 I陣列
- 程式碼隨想錄陣列二刷:長度最小的子陣列(滑動視窗)陣列