ACM-ICPC(10/21)
写一发后缀数组套路题,看起来简单,写起来要人命哦~~~
总共13题。
分两天debug吧,有点累了~~~
suffix(后缀数组的应用)
sa[i] :排名第 i 的后缀在哪(i 从 1 开始)
rank[i]:后缀 i 排第几 (i 从 0 开始)
height[i]:排名为 i 和 i-1 的两个后缀的最长公共前缀(LCP)长度 (i 从 2 开始)
模板:加上RMQ操作
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include <algorithm>
-
-
- using namespace std;
-
- const int maxn = +;
-
- int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
- int sa[maxn];
- int r[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,*t;
- for(i=; i<m; i++) ws[i]=;
- for(i=; i<n; i++) ws[x[i]=r[i]]++;
- for(i=; i<m; i++) ws[i]+=ws[i-];
- for(i=n-; i>=; i--) sa[--ws[x[i]]]=i;
- for(j=,p=; p<n; j*=,m=p)
- {
- for(p=,i=n-j; i<n; i++) y[p++]=i;
- for(i=; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
- for(i=; i<n; i++) wv[i]=x[y[i]];
- for(i=; i<m; i++) ws[i]=;
- for(i=; i<n; i++) ws[wv[i]]++;
- for(i=; i<m; i++) ws[i]+=ws[i-];
- for(i=n-; i>=; i--) sa[--ws[wv[i]]]=y[i];
- for(t=x,x=y,y=t,p=,x[sa[]]=,i=; i<n; i++)
- x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
- }
- return;
- }
- int ranks[maxn],height[maxn];
- void calheight(int *r,int *sa,int n)
- {
- int i,j,k=;
- for(i=; i<=n; i++) ranks[sa[i]]=i;
- for(i=; i<n; height[ranks[i++]]=k)
- for(k?k--:,j=sa[ranks[i]-]; r[i+k]==r[j+k]; k++);
- return;
- }
-
-
- char str[maxn];
-
- int f[maxn][];
- void init(int len) {
- for(int i = ; i <= len; i++) f[i][] = height[i];
- for(int s = ; (<<s)<=len; s++) {
- int tmp = (<<s);
- for(int i = ; i+tmp-<=len; i++) {
- f[i][s] = min(f[i][s-],f[i+tmp/][s-]);
- }
- }
- }
-
- int cal(int l,int r) {
- int len = log2(r-l+);
- int ans = min(f[l][len],f[r-(<<len)+][len]);
- return ans;
- }
-
-
-
- int main()
- {
- freopen("in.txt","r",stdin);
-
- scanf("%s",str);
- int n = strlen(str);
-
- for(int i = ; i < n; i++)
- r[i] = str[i] - 'a' + ;
- da(r,sa,n+,);
- calheight(r,sa,n);
-
- for(int i = ; i <= n; i++) {
- printf("%d ",sa[i]);
- }
- puts("");
-
- for(int i = ; i < n; i++) {
- printf("%d ",ranks[i]);
- }
- puts("");
-
- for(int i = ; i <= n; i++) {
- printf("%d ",height[i]);
- }
- puts("");
-
- init(n);
-
- //height 上的 RMQ(); 从 2开始;
- printf("%d\n",cal(,));
- return ;
- }
例题一:最长公共前缀
给定一个字符串,询问某两个后缀的最长公共前缀。
分析:根据图,某两个后缀的LCP,是一个区间的RMQ;(也是定理)
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include <algorithm>
-
-
- using namespace std;
-
- const int maxn = +;
-
- int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
- int sa[maxn];
- int r[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,*t;
- for(i=; i<m; i++) ws[i]=;
- for(i=; i<n; i++) ws[x[i]=r[i]]++;
- for(i=; i<m; i++) ws[i]+=ws[i-];
- for(i=n-; i>=; i--) sa[--ws[x[i]]]=i;
- for(j=,p=; p<n; j*=,m=p)
- {
- for(p=,i=n-j; i<n; i++) y[p++]=i;
- for(i=; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
- for(i=; i<n; i++) wv[i]=x[y[i]];
- for(i=; i<m; i++) ws[i]=;
- for(i=; i<n; i++) ws[wv[i]]++;
- for(i=; i<m; i++) ws[i]+=ws[i-];
- for(i=n-; i>=; i--) sa[--ws[wv[i]]]=y[i];
- for(t=x,x=y,y=t,p=,x[sa[]]=,i=; i<n; i++)
- x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
- }
- return;
- }
- int ranks[maxn],height[maxn];
- void calheight(int *r,int *sa,int n)
- {
- int i,j,k=;
- for(i=; i<=n; i++) ranks[sa[i]]=i;
- for(i=; i<n; height[ranks[i++]]=k)
- for(k?k--:,j=sa[ranks[i]-]; r[i+k]==r[j+k]; k++);
- return;
- }
-
-
- char str[maxn];
-
- int f[maxn][];
- void init(int len) {
- for(int i = ; i <= len; i++) f[i][] = height[i];
- for(int s = ; (<<s)<=len; s++) {
- int tmp = (<<s);
- for(int i = ; i+tmp-<=len; i++) {
- f[i][s] = min(f[i][s-],f[i+tmp/][s-]);
- }
- }
- }
-
- int cal(int l,int r) {
- int len = log2(r-l+);
- int ans = min(f[l][len],f[r-(<<len)+][len]);
- return ans;
- }
-
-
-
- int main()
- {
- freopen("in.txt","r",stdin);
-
- scanf("%s",str);
- int n = strlen(str);
-
- for(int i = ; i < n; i++)
- r[i] = str[i] - 'a' + ;
- da(r,sa,n+,);
- calheight(r,sa,n);
-
- for(int i = ; i <= n; i++) {
- printf("%d ",sa[i]);
- }
- puts("");
-
- for(int i = ; i < n; i++) {
- printf("%d ",ranks[i]);
- }
- puts("");
-
- for(int i = ; i <= n; i++) {
- printf("%d ",height[i]);
- }
- puts("");
-
- init(n);
-
- int l,r; // 询问后缀L,R的最长公共前缀,从0开始
-
- scanf("%d%d",&l,&r);
- l = ranks[l];
- r = ranks[r];
-
- if(l>r) swap(l,r);
-
- l++;
- printf("%d\n",cal(l,r));
-
- return ;
- }
例题二:可以重叠的最长重复子串
给定一个字符串,求最长的重复子串(出现了多次>1),这两个子串可以重叠。
分析:子串可以写成一个后缀,题目可以转换为求:最长的两个后缀的最长公共前缀。任意两个后缀的LCP,都是height数组里面某一段的最小值,那么这个值一定不大于height 的最大值。
- int ans = -;
- for(int i = ; i <= n; i++)
- ans = max(ans,height[i]);
例题三:不可重叠最长重复子串(pku1743)
给定一个字符串,求最长重复子串,这两个子串不能重叠。(当然原题题意没这么简单咯~~~原题是音乐家演奏,求两组最长的旋律,要求这两组旋律一下(只可以相差一个常数))
我这里写字符串的,其实转换过来很简单的(考虑其差值,就转换过来了)
分析:遇到不重叠——二分分组。
先二分答案,把问题变成一个判定性题目,将排序排序后的后缀按照mid 分成若干组,每组的后缀自检的height>=mid,每个区间内找两个后缀满足不重叠即可。
原理:可以看出,游戏王成为最长公共前缀>=mid 的两个后缀,一定在一个分组里面。这个分组里面查不相交的两个位置。
- int main()
- {
- freopen("in.txt","r",stdin);
-
- scanf("%s",str);
- int n = strlen(str);
-
- for(int i = ; i < n; i++) r[i] = str[i] - 'a' + ;
-
- da(r,sa,n+,);
- calheight(r,sa,n);
-
- int l = ,r= n;
- int ans = ;
- while(l<=r) {
- int mid = l + (r-l)/;
- int L = inf,R= -inf;
- bool flag = false;
- for(int i = ; i <= n; i++) {
- if(height[i]>=mid) { //按照 mid 分组
- L = min(L,sa[i]);
- L = min(L,sa[i-]);
- R = max(R,sa[i]);
- R = max(R,sa[i-]);
- }
- else
- {
- if(L+mid+<=R) {
- flag = true;
- ans = mid;
- }
- L = inf;
- R = -inf;
- }
- }
-
- if(L+mid+<=R) flag = true;
- if(flag) l = mid+;
- else r = mid - ;
- }
-
- printf("%d\n",ans);
-
- return ;
- }
例题四:可重叠k次最长重复子串(pku3261)
给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠。
分析:此题可以重叠,二分答案,将后缀分组,由例题三和例题二,可以看出,只要判断是否存在一个分组使得其中元素>=k(重复k次嘛~~~)
- int main()
- {
- freopen("in.txt","r",stdin);
-
- scanf("%s",str);
- int n = strlen(str);
- int k;
- scanf("%d",&k);
-
- for(int i = ; i < n; i++) r[i] = str[i] - 'a' + ;
-
- da(r,sa,n+,);
- calheight(r,sa,n);
-
- for(int i = ; i<= n;i++)
- printf("%d ",height[i]);
- puts("");
-
- int l = ,r= n;
- int ans = ;
- while(l<=r) {
- int mid = l + (r-l)/;
- int L = inf,R= -inf;
- bool flag = false;
- int cnt = ;
- for(int i = ; i <= n; i++) {
- if(height[i]>=mid) { //按照 mid 分组
- cnt++;
- }
- else
- {
- if(cnt>=k) {
- flag = true;
- ans = mid;
- }
- L = inf;
- R = -inf;
- cnt = ;
- }
- }
- if(flag) l = mid+;
- else r = mid - ;
- }
-
- printf("%d\n",ans);
-
- return ;
- }
例题五:子串的个数(spoj694,spoj705)
给定一个字符串,求不相同的子串个数。
这个题今年多校考过~~~~不过当时GG了。
每一个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数。
每个后缀产生n-sa[i] 个前缀,其中有height[i] 已经与前面重复~~~
- int main()
- {
- freopen("in.txt","r",stdin);
-
- scanf("%s",str);
- int n = strlen(str);
-
- for(int i = ; i < n; i++) r[i] = str[i] - 'a' + ;
-
- da(r,sa,n+,);
- calheight(r,sa,n);
-
- for(int i = ; i<= n;i++)
- printf("%d ",height[i]);
- puts("");
-
- int cnt = n - sa[];
-
- for(int i = ; i <= n; i++)
- cnt = cnt + n - sa[i] - height[i];
- printf("%d\n",cnt);
-
- return ;
- }
例题六:最长回文子串(ural11297)
给定一个字符串,求最长回文子串。
先搞一发Manacher;
- #include <bits/stdc++.h>
- using namespace std;
-
- const int maxn = ;
-
- char instr[maxn],str[maxn*];
- int rad[maxn*];
-
-
- int Manacher()
- {
- int i,j,maxx;
- int n = strlen(instr);
- memset(str,'#',sizeof(str));
- for(i=;i<n;i++)
- str[(i+)<<] = instr[i];
-
- n = (n+)<<;
- str[n] = '$';
- int maxRad;
- maxRad = j = maxx = ;
- for(i = ;i<n;i++)
- {
- if(i<maxx)
- rad[i] = min(rad[*j-i],maxx-i);
- else rad[i] = ;
-
- while(str[i-rad[i]]==str[i+rad[i]])
- rad[i] ++;
- if(maxRad<rad[i])
- maxRad = rad[i];
- if(rad[i]+i>maxx)
- {
- j = i;
- maxx = rad[i] + i;
- }
-
- }
- return maxRad;
-
- }
-
- int main()
- {
- int t;
- scanf("%d",&t);
- while(t--)
- {
- scanf("%s",instr);
- printf("%d\n",Manacher()-);
- }
- return ;
- }
但是,后缀数组的思路是非常重要的,重要到关于两个字符串的题目,extend_kmp很难的话,那么基本上就是后缀数组了~~~
分析:回文——将字符串倒着加到后面,枚举回文的中心点,而只要考虑回文的一侧,另一侧则在对称面,这两个后缀求LCP~~~
- int main()
- {
- freopen("in.txt","r",stdin);
-
- scanf("%s",str);
-
- int n = strlen(str);
- int tmpn = n;
- str[n] = '$';
-
- for(int i = n+,j=; i <= *n; i++,j++)
- str[i] = str[n--j];
-
- puts(str);
-
- for(int i = ; i < n; i++) r[i] = str[i] - 'a' + ;
- r[n] = ;
- for(int i = n+; i < *n+; i++) r[i] = str[i] - 'a' + ;
- n = strlen(str);
- //
- // da(r,sa,n+1,300);
- // calheight(r,sa,n);
- //
- // for(int i =2 ; i<= n;i++)
- // printf("%d ",height[i]);
- // puts("");
-
-
- da(r,sa,n,);
- calheight(r,sa,n);
-
- for(int i = ; i <= n; i++)
- printf("%d ",sa[i]);
- puts("");
-
- init(n);
-
- int ans = ;
- for(int i = ; i < tmpn; i++) { //枚举中心
- int l = i;
- int r = n - i - ;
- l = ranks[l];
- r = ranks[r];
-
- l++;
-
- int lcp = cal(l,r); //回文是奇数
- if(lcp*->ans) {
- ans = lcp * -;
- }
-
- l = i;
- if(l!=tmpn) {
- l++;
- r = n - l - ;
- l = ranks[l];
- r = ranks[r];
- l++;
- lcp = cal(l,r);
- ans = max(ans,lcp*);
- }
-
-
- }
- printf("%d\n",ans);
-
-
- return ;
- }
ACM-ICPC(10/21)的更多相关文章
- hduoj 4712 Hamming Distance 2013 ACM/ICPC Asia Regional Online —— Warmup
http://acm.hdu.edu.cn/showproblem.php?pid=4712 Hamming Distance Time Limit: 6000/3000 MS (Java/Other ...
- 2015 ACM / ICPC 亚洲区域赛总结(长春站&北京站)
队名:Unlimited Code Works(无尽编码) 队员:Wu.Wang.Zhou 先说一下队伍:Wu是大三学长:Wang高中noip省一:我最渣,去年来大学开始学的a+b,参加今年区域赛之 ...
- ACM/ICPC 之 BFS(离线)+康拓展开(TSH OJ-玩具(Toy))
祝大家新年快乐,相信在新的一年里一定有我们自己的梦! 这是一个简化的魔板问题,只需输出步骤即可. 玩具(Toy) 描述 ZC神最擅长逻辑推理,一日,他给大家讲述起自己儿时的数字玩具. 该玩具酷似魔方, ...
- ACM ICPC 2015 Moscow Subregional Russia, Moscow, Dolgoprudny, October, 18, 2015 D. Delay Time
Problem D. Delay Time Input file: standard input Output file: standard output Time limit: 1 second M ...
- 【转】lonekight@xmu·ACM/ICPC 回忆录
转自:http://hi.baidu.com/ordeder/item/2a342a7fe7cb9e336dc37c89 2009年09月06日 星期日 21:55 初识ACM最早听说ACM/ICPC ...
- hduoj 4715 Difference Between Primes 2013 ACM/ICPC Asia Regional Online —— Warmup
http://acm.hdu.edu.cn/showproblem.php?pid=4715 Difference Between Primes Time Limit: 2000/1000 MS (J ...
- hduoj 4707 Pet 2013 ACM/ICPC Asia Regional Online —— Warmup
http://acm.hdu.edu.cn/showproblem.php?pid=4707 Pet Time Limit: 4000/2000 MS (Java/Others) Memory ...
- hduoj 4706 Children's Day 2013 ACM/ICPC Asia Regional Online —— Warmup
http://acm.hdu.edu.cn/showproblem.php?pid=4706 Children's Day Time Limit: 2000/1000 MS (Java/Others) ...
- 2016 ACM/ICPC Asia Regional Qingdao Online 1001/HDU5878 打表二分
I Count Two Three Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- 2016 ACM/ICPC Asia Regional Shenyang Online 1009/HDU 5900 区间dp
QSC and Master Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) ...
随机推荐
- 理解fig,ax = plt.subplots()
fig = plt.figure() ax = fig.add_subplot(1,1,1) fig, ax = plt.subplots(1,3),其中参数1和3分别代表子图的行数和列数,一共有 1 ...
- Java开发环境搭建——IntelliJ Idea开发环境
IntelliJ Idea版本选择由于公司使用JDK7,所以我选择安装Version 2016.1.4(手动安装试验出来的,最新版的2016.1.4启动时提示需要安装JDK8)下载 前面说明有误,其实 ...
- go语言解析网页利器goquery使用教程(爬虫必备)
某些时候需要爬取网页中指定信息时,通常需要一些框架解析网页行成dom模型,然后来操作节点来获取相应的信息.在java中很显然就是Jsoup,而在Golang里,应该就是这个goquery了吧. goq ...
- CountDownLatch 多线程,等待所有线程结束
CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 主要方法 public CountDownLatch(int count); 构造 ...
- CVE-2018-7600-Drupal远程代码执行漏洞-Render API
今天学习一下Drupal的另一个漏洞,由于渲染数组不当造成的漏洞 poc: url:http://localhost/drupal-8.5.0/user/register?element_parent ...
- 微信小程序开发踩坑记录
1.由于小程序wx.request()方法是异步的,在app.js执行ajax后,各分页加载app.js的全局数据时,无法按顺序加载.例: //app.js App({ ajax:function() ...
- 【tomcat】关于tomcat的使用:将tomcat加入系统服务列表
一.下载TOMCAT 选择合适的版本进行下载: http://tomcat.apache.org/ 解压zip文件得到tomcat目录: 二.添加CATALINA_HOME到环境变量 service. ...
- A bug about RecipientEditTextView
- Steps to reproduce the problem. Pre-condition:the threshold of the RecipientEditTextView is set to ...
- easyui datebox 精确到秒并且显示值
其实这个官网文档有的,也就不啰嗦了,直接贴官网的代码吧. <input id="dt" type="text" name="birthday&q ...
- XMLHttpRequest.responseType
"arraybuffer" "blob" "document" "json" "text"