poj 3415 Common Substrings——后缀数组+单调栈
题目:http://poj.org/problem?id=3415
因为求 LCP 是后缀数组的 ht[ ] 上的一段取 min ,所以考虑算出 ht[ ] 之后枚举每个位置作为右端的贡献。
一开始想的是把两个数组接起来(中间加个逗号之类的,就能算出正确的 LCP ),不加区分地算了贡献之后再分别减去两个数组自己内部的贡献。
看看题解,得知可以在那个接起来的数组上分别算 a 与前面的 b 、b 与前面的 a 的贡献,就不用容斥了。
考虑怎么算贡献。一开始想的是取 min 一定越取越小,所以维护双指针卡在取min>=K的最靠前位置;新加入一个元素的时候二分找到第一个取min后比自己小的位置,改一下该位置到自己位置的贡献(现在看来好像不用维护那个双指针也行?);
看看题解,原来可以用单调栈。就相当于维护一下单调栈的“面积”一样。
不过有一点麻烦的是 i 位置能否产生贡献是看 i+1 位置到末尾位置的 min ;这样求“面积”就要费点心;不过想到可以让 ht[ i ] = ht[ i+1 ] ,这样的话正常求面积就行了!累计到答案上之后再把当前位置入队。
注意有大写字母。而且 poj 上编译不过 swap( rk , tp ) ,写 memcpy 就行了。
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #define ll long long
- using namespace std;
- const int N=1e5+,M=N<<;
- int n,m,s[M],sa[M],rk[M],tp[M],tx[M],ht[M];
- int sta[M],top,wd1[M],wd2[M]; ll sm1[M],sm2[M];
- char a[N],b[N];
- int Mx(int a,int b){return a>b?a:b;}
- void Rsort(int n,int nm)
- {
- for(int i=;i<=nm;i++)tx[i]=;
- for(int i=;i<=n;i++)tx[rk[i]]++;
- for(int i=;i<=nm;i++)tx[i]+=tx[i-];
- for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
- }
- void get_sa(int n)
- {
- int nm=;
- for(int i=;i<=n;i++)tp[i]=i,rk[i]=s[i];
- Rsort(n,nm);
- for(int k=;k<=n;k<<=)
- {
- int tot=;
- for(int i=n-k+;i<=n;i++)tp[++tot]=i;
- for(int i=;i<=n;i++)
- if(sa[i]>k)tp[++tot]=sa[i]-k;
- Rsort(n,nm);
- memcpy(tp,rk,sizeof rk);
- /*swap(rk,tp);*/nm=;rk[sa[]]=;
- for(int i=,u,v;i<=n;i++)
- {
- u=sa[i]+k;v=sa[i-]+k;if(u>n)u=;if(v>n)v=;
- rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[u]==tp[v])?nm:++nm;
- }
- if(nm==n)break;
- }
- }
- void get_ht(int n)
- {
- int k=,j;
- for(int i=;i<=n;i++)
- {
- for(j=sa[rk[i]-],k?k--:;i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
- ht[rk[i]]=k;
- }
- }
- int main()
- {
- while()
- {
- int lm;scanf("%d",&lm);if(!lm)return ;
- scanf("%s",a+);scanf("%s",b+);
- n=strlen(a+); m=strlen(b+); int tn=n+m+;
- for(int i=;i<=n;i++)s[i]=a[i]-'A'+;
- s[n+]=;
- for(int i=n+,j=;i<=tn;i++,j++)s[i]=b[j]-'A'+;
- get_sa(tn);get_ht(tn);
- for(int i=;i<tn;i++)ht[i]=ht[i+];
- top=; ll ans=;
- for(int i=;i<=tn;i++)
- {
- if(sa[i]<=n)ans+=sm2[top]; else if(sa[i]>n+)ans+=sm1[top];
- int lj1=,lj2=;
- while(top&&ht[i]<=ht[sta[top]])
- lj1+=wd1[top],lj2+=wd2[top],top--;
- sta[++top]=i;
- if(sa[i]<=n)lj1++; else if(sa[i]>n+)lj2++;
- wd1[top]=lj1; sm1[top]=sm1[top-]+(ll)lj1*Mx(,ht[i]-lm+);
- wd2[top]=lj2; sm2[top]=sm2[top-]+(ll)lj2*Mx(,ht[i]-lm+);
- }
- printf("%lld\n",ans);
- }
- return ;
- }
poj 3415 Common Substrings——后缀数组+单调栈的更多相关文章
- poj 3415 Common Substrings —— 后缀数组+单调栈
题目:http://poj.org/problem?id=3415 先用后缀数组处理出 ht[i]: 用单调栈维护当前位置 ht[i] 对之前的 ht[j] 取 min 的结果,也就是当前的后缀与之前 ...
- poj 3415 Common Substrings 后缀数组+单调栈
题目链接 题意:求解两个字符串长度 大于等于k的所有相同子串对有多少个,子串可以相同,只要位置不同即可:两个字符串的长度不超过1e5; 如 s1 = "xx" 和 s2 = &qu ...
- poj 3415 Common Substrings - 后缀数组 - 二分答案 - 单调栈
题目传送门 传送点I 传送点II 题目大意 给定串$A, B$,求$A$和$B$长度大于等于$k$的公共子串的数量. 根据常用套路,用一个奇怪的字符把$A$,$B$连接起来,然后二分答案,然后按mid ...
- POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)
Description A substring of a string T is defined as: T( i, k)= TiTi+1... Ti+k-1, 1≤ i≤ i+k-1≤| T|. G ...
- POJ3415 Common Substrings —— 后缀数组 + 单调栈 公共子串个数
题目链接:https://vjudge.net/problem/POJ-3415 Common Substrings Time Limit: 5000MS Memory Limit: 65536K ...
- POJ 3415 Common Substrings 后缀数组+并查集
后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height 求完之后按height值从大往小合并. height值代表的是 sa[i]和sa[i ...
- POJ - 3415 Common Substrings (后缀数组)
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 s ...
- poj 3415 Common Substrings【SA+单调栈】
把两个串中间加一个未出现字符接起来,然后求SA 然后把贡献统计分为两部分,在排序后的后缀里,属于串2的后缀和排在他前面属于串1的后缀的贡献和属于串1的后缀和排在他前面属于串2的后缀的贡献 两部分分别作 ...
- POJ 3415 Common Substrings ——后缀数组
[题目分析] 判断有多少个长度不小于k的相同子串的数目. N^2显然是可以做到的. 其实可以维护一个关于height的单调栈,统计一下贡献,就可以了. 其实还是挺难写的OTZ. [代码] #inclu ...
随机推荐
- [nowcoder]再编号
链接:https://www.nowcoder.com/acm/contest/158/C 每变化一次,tot=tot*(n-1),且每两个数之差delta*=-1,直接根据这两个性质暴力循环1000 ...
- HDU 1532 --&&-- POJ1273 dinic 算法
学长的代码#include<stdio.h> #include<string.h> #include<queue> #include<algorithm> ...
- Hive-行转列(explode)
场景:通过parseHtml UDF解析一串HTML,返回一以 @@ 分割的字符串,使用split分割字符串进数组中,然后将数组的元素转列. 开始的写法 SELECT id, legal_person ...
- PAT1076. Forwards on Weibo (30)
使用DFS出现超时,改成bfs DFS #include <iostream> #include <vector> #include <set> using nam ...
- Hibernate缓存何时使用和如何使用
http://developer.51cto.com/art/201202/315922.htm 1. 关于hibernate缓存的问题: 1.1. 基本的缓存原理 Hibernate缓存分为二级, ...
- [JavaScript]对象创建方法
1.使用Object或对象字面量创建对象 (1)使用Object创建对象 var cat= new Object(); cat.name = "Tom"; cat.color= & ...
- c语言中的string
1. strlen(char const* s); 函数传入的是c风格字符串(即以‘\0’结尾的字符数组),返回的长度为size_t(即unsigned int),其长度不包括'\0'. 2. str ...
- f5 ddos cc——Mitigating DDoS Attacks with F5 Technology
摘自:https://f5.com/resources/white-papers/mitigating-ddos-attacks-with-f5-technology Mitigating Appli ...
- Node.js小白开路(一)-- events篇
时间或许可以说是以JS来理解世界的基础,针对于某一个情况对象会做出何种反应,反应之后会做出何种处理,以及这一事件衍生出来了哪一些变化. 大多数 Node.js 核心 API 都采用惯用的异步事件驱动架 ...
- LeetCode OJ:Reverse Linked List (反转链表)
Reverse a singly linked list. 做II之前应该先来做1的,这个倒是很简单,基本上不用考虑什么,简单的链表反转而已: /** * Definition for singly- ...