HDU5769-Substring-多校#4-1006-后缀数组

给定一个字符x和一个字符串。要求输出包含此字符的所有不同字串。

后缀数组可以计算一个字符串的所有不同字串,理解了原理就能做这题了。

对于每一个后缀i,将产生len-sa[i]-hight[i]的前缀,累加起来就是所有不同字串。这里要求字串必须包含x

也就是对于每一个后缀i,要减去不含x的前缀。

保存每一个x的位置,用lower_bound查询在此后缀中的第一个x,然后之前的都不计算到贡献当中。

dc3敲起来太慢了

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #define LL long long
  5 //using namespace std;
  6
  7 const int maxn = 1e5+100;
  8 #define F(x) ((x)/3+((x)%3 == 1?0:tb))
  9 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
 10 int wa[maxn*3],wb[maxn*3],wv[maxn*3],wss[maxn*3];
 11
 12 int c0(int *r,int a,int b)
 13 {
 14     return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];
 15 }
 16 int c12(int k,int *r,int a,int b)
 17 {
 18     if(k == 2)
 19         return r[a] < r[b] ||(r[a] == r[b] && c12(1,r,a+1,b+1));
 20     else
 21         return r[a] < r[b] ||(r[a] == r[b] && wv[a+1] < wv[b+1]);
 22 }
 23 void sort(int *r,int *a,int *b,int n,int m)
 24 {
 25     int i;
 26     for(i=0;i<n;i++) wv[i] = r[a[i]];
 27     for(i=0;i<m;i++) wss[i] = 0;
 28     for(i=0;i<n;i++) wss[wv[i]]++;
 29     for(i=1;i<m;i++) wss[i] += wss[i-1];
 30     for(i=n-1;i>=0;i--)b[--wss[wv[i]] ] = a[i];
 31 }
 32 void dc3(int *r,int *_sa,int n,int m)
 33 {
 34     int i,j,*rn = r+n;
 35     int *san = _sa+n,ta = 0,tb=(n+1)/3,tbc=0,p;
 36     r[n] = r[n+1] = 0;
 37     for(i=0;i<n;i++) if(i%3 != 0) wa[tbc++] = i;
 38     sort(r+2,wa,wb,tbc,m);
 39     sort(r+1,wb,wa,tbc,m);
 40     sort(r,wa,wb,tbc,m);
 41     for(p=1,rn[F(wb[0])] = 0,i=1;i<tbc;i++)
 42         rn[F(wb[i])] = c0(r,wb[i-1],wb[i]) ? p-1:p++;
 43     if(p < tbc) dc3(rn,san,tbc,p);
 44     else for(i=0;i<tbc;i++) san[rn[i]] = i;
 45     for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++] = san[i]*3;
 46     if(n%3==1) wb[ta++] = n-1;
 47     sort(r,wb,wa,ta,m);
 48     for(i=0;i<tbc;i++) wv[wb[i]=G(san[i]) ] = i;
 49     for(i=0,j=0,p=0;i<ta&&j<tbc;p++)
 50         _sa[p] = c12(wb[j]%3,r,wa[i],wb[j]) ? wa[i++]:wb[j++];
 51     for(;i<ta;p++) _sa[p] = wa[i++];
 52     for(;j<tbc;p++) _sa[p] = wb[j++];
 53 }
 54 void da(int str[],int _sa[],int _rank[],int _height[],int n,int m)
 55 {
 56     for(int i=n;i<n*3;i++) str[i] = 0;
 57     dc3(str,_sa,n+1,m);
 58     int i,j,k = 0;
 59     for(i=1;i<=n;i++) _rank[_sa[i]] = i;
 60     for(i=0;i<n;i++)
 61     {
 62         if(k) k--;
 63         j = _sa[_rank[i]-1 ];
 64         while(str[i+k] == str[j+k]) k++;
 65         _height[_rank[i]] = k;
 66     }
 67 }
 68
 69 int T;
 70 int sa[3*maxn],hehe[3*maxn],rank[maxn],height[maxn];
 71 int x;
 72 char line[3*maxn];
 73
 74 void debug(int n)
 75 {
 76     for(int i=0;i<=n;i++)
 77     {
 78         printf("sa:%d rank:%d height:%d\n",sa[i],rank[i],height[i]);
 79     }
 80 }
 81
 82 int main()
 83 {
 84     //freopen("input.txt","r",stdin);
 85     scanf("%d ",&T);
 86     int cas = 0;
 87     while(T--)
 88     {
 89         scanf(" %c %s",&x,line);
 90         int len = strlen(line);
 91         for(int i=0;i<len;i++) hehe[i] = line[i];
 92         int ch[maxn],cnt = 0;
 93         for(int i=0;i<len;i++)
 94         {
 95             if(line[i] == x) ch[cnt++] = i;
 96         }
 97         ch[cnt++] = len;
 98         da(hehe,sa,rank,height,len,300);
 99         //debug(len);
100         LL ans = 0;
101         for(int i=1;i<=len;i++)
102         {
103             int pos = ch[std::lower_bound(ch,ch+cnt,sa[i]) - ch] - sa[i];
104             ans += len -sa[i]  ;
105             ans -= std::max(pos,height[i]);
106         }
107         printf("Case #%d: %I64d\n",++cas,ans);
108     }
109 }
时间: 2024-10-26 23:50:21

HDU5769-Substring-多校#4-1006-后缀数组的相关文章

poj 3693 Maximum repetition substring(08合肥 RMQ+后缀数组)

传送门:http://poj.org/problem?id=3693 题目:给出一个串,求重复次数最多的连续重复子串: 分析: 枚举重复单元的长度,然后理所当然的枚举起点.利用rmq处理,后缀i,i+l的最长前缀. lcp/l+1,为当前相邻l长度单元的串的重复次数,但是由于i+=l,提高了效率,但是i不一定刚好是重复串的起点,所以如果r%l!=0,把串往前移l-r%l个单位.找到最大的重复次数,然后利用sa数组的排名(1-n),,可以字典序输出. 详细链接:http://blog.csdn.n

Lexicographical Substring Search SPOJ - SUBLEX (后缀数组)

Lexicographical Substrings Search \[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \] 题意 给出一个字符串,求出这个字符串上字典序第 \(k\) 小的子串. 思路 对于给出的字符串,求出后缀数组,根据后缀数组的 \(height\) 数组,我们可以很容易得到一个字符的总子串个数是 \(\sum_{i=1}^{n} (n-sa[i]+1+height[i])\),利用这个式子,就可以求出第 \(k\) 小

2016暑假多校联合---Substring(后缀数组)

2016暑假多校联合---Substring Problem Description ?? is practicing his program skill, and now he is given a string, he has to calculate the total number of its distinct substrings. But ?? thinks that is too easy, he wants to make this problem more interesti

2016多校联合训练4 F - Substring 后缀数组

Description ?? is practicing his program skill, and now he is given a string, he has to calculate the total number of its distinct substrings. But ?? thinks that is too easy, he wants to make this problem more interesting. ?? likes a character X very

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>

HDU 1403 Longest Common Substring(后缀数组,最长公共子串)

hdu题目 poj题目 参考了 罗穗骞的论文<后缀数组——处理字符串的有力工具> 题意:求两个序列的最长公共子串 思路:后缀数组经典题目之一(模版题) //后缀数组sa:将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置.简单的记忆就是“排第几的是谁”. //名次数组rank:rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次.则 若 sa[i]=j,则 rank[j]=i.简单的记忆就是“你排第几”

POJ 3693 Maximum repetition substring (后缀数组)

题目大意: 求出字典序最小,重复次数最多,的子串. 思路分析: RMQ + height 数组可以求出任意两个后缀的lcp 我们枚举答案字符串的重复的长度. 如果这个字符串的长度为 l ,而且这个字符串出现过两次或两次以上 那么你会发现在原串中  str[0] str[l] str[2*l] ....肯定有相邻的两个被包含在重复的串中. 我们求出这两个相邻的后缀的lcp 我们上面仅仅说的是被包含在重复的串中,但并不一定就是以 str[0], str[l],str[2*l]....为起点的. 那我

hdu_1403_Longest Common Substring(后缀数组的应用)

题目链接:hdu_1403_Longest Common Substring 题意: 给你两个字符串,然你找最长的公共子串 题解: 后缀数组的经典应用,要找两个字符串的公共子串,那么就相当于找两个串的后缀的最长公共前缀,我们将两个字符串拼接在一起,中间插一个特殊字符 然后我们考虑height数组,height数组存的是排i和i-1的最长前缀,如果sa[i]和sa[i-1]在特殊字符的两边,那么这个height[i]记录的就是这两个串的最长 子串,然后扫一遍height数组更新一下答案就行了 1

HDU 1403 Longest Common Substring(后缀数组啊 求最长公共子串 模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 Problem Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", a

POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a