CF IndiaHacks 2016 F Paper task 后缀数组
题目链接:http://codeforces.com/problemset/problem/653/F
大意是给出一个只包含'('和')'的括号串,求有多少不同的子串是合法的括号串
解法:对于每一个后缀,需要能够求出这个后缀有多少前缀是合法的括号串,这个可以用O(log n)复杂度的二分来解决。注意,二分的范围并不是整个后缀,因为如果将'('视作+1, ')'视作-1,则一个合法的括号串必须时刻不能小于0。所以可以在ST表上二分出合法范围,在这个范围内去统计有多少合法串(即'('与')'正负相消)。求出一个区间内有多少数字值为x可以对一个保存值和位置的pair数组排序后二分。
那么剩下的问题就是如何去重,由于height数组中记录的是排名相邻的两个后缀的最长公共前缀LCP,那么每一次统计只要根据这个信息减去相应重复统计的数量即可。
下面的代码中统计了两次num,是直接对上述思路的实现,其实是可以合并的。
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set> using namespace std; const int N=+;
char s[N];
int sum[N];
vector< pair<int,int> >v; int preLog2[N];
struct SparseTable {
#define T int
#define MAXN N
static T MIN(T a,T b){return a<b?a:b;}
static T MAX(T a,T b){return a>b?a:b;}
SparseTable() {
if (!preLog2[]){
preLog2[]=;
for (int i=;i<MAXN;i++)
preLog2[i]=preLog2[i>>]+;
}
}
T dp[MAXN][];
T (*cmp) (T,T);
void setMin(){cmp=MIN;}
void setMax(){cmp=MAX;}
void init(int n,T *val) {
for (int i=;i<n;i++)
dp[i][]=val[i];
for (int j=;(<<j)<=n;j++) {
int k=<<(j-);
for (int i=;i+k<n;i++)
dp[i][j]=cmp(dp[i][j-],dp[i+k][j-]);
}
}
T query(int a,int b) {
if (a>b) swap(a,b);
int k=preLog2[b-a+];
return cmp(dp[a][k],dp[b-(<<k)+][k]);
}
#undef MAXN
#undef T
}tab;
struct SuffixArray {
int wa[N], wb[N], cnt[N], wv[N];
int rk[N], height[N];
int sa[N];
bool cmp(int r[], int a, int b, int l) {
return r[a] == r[b] && r[a+l] == r[b+l];
}
void calcSA(char r[], int n, int m) {
int i, j, p, *x = wa, *y = wb;
for (i = ; i < m; ++i) cnt[i] = ;
for (i = ; i < n; ++i) cnt[x[i]=r[i]]++;
for (i = ; i < m; ++i) cnt[i] += cnt[i-];
for (i = n-; i >= ; --i) sa[--cnt[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) cnt[i] = ;
for (i = ; i < n; ++i) cnt[wv[i]]++;
for (i = ; i < m; ++i) cnt[i] += cnt[i-];
for (i = n-; i >= ; --i) sa[--cnt[wv[i]]] = y[i];
for (swap(x, y), p = , x[sa[]] = , i = ; i < n; ++i)
x[sa[i]] = cmp(y, sa[i-], sa[i], j) ? p- : p++;
}
}
void calcHeight(char r[], int n) {
int i, j, k = ;
for (i = ; i <= n; ++i) rk[sa[i]] = i;
for (i = ; i < n; height[rk[i++]] = k)
for (k?k--:, j = sa[rk[i]-]; r[i+k] == r[j+k]; k++);
}
int lcp(int a,int b,int len) {
if (a==b) return len-a;
int ra=rk[a],rb=rk[b];
if (ra>rb) swap(ra,rb);
return queryST(ra+,rb);
}
int st[N][];
int preLog2[N];
void initST(int n) {
for (int i=;i<=n; i++)
st[i][]=height[i];
for (int j=;(<<j)<=n; j++) {
int k=<<(j-);
for (int i=; i+k<=n; i++)
st[i][j]=min(st[i][j-],st[i+k][j-]);
}
preLog2[]=;
for(int i=;i<=n;i++){
preLog2[i]=preLog2[i>>]+;
}
}
int queryST(int a,int b) {
if (a>b) swap(a,b);
int dis=b-a+;
int k=preLog2[dis];
return min(st[a][k],st[b-(<<k)+][k]);
}
void solve(int n) {
long long ret=;
for (int i=;i<=n;i++) {
if (s[sa[i]]==')') continue;
int l=sa[i],h=n-,p=n;
while (l<=h) {
int m=(l+h)>>;
if (tab.query(l,m)<sum[sa[i]]-) {
p=m;
h=m-;
}
else
l=m+;
}
p--;
int num=upper_bound(v.begin(),v.end(),make_pair(sum[sa[i]]-,p))-lower_bound(v.begin(),v.end(),make_pair(sum[sa[i]]-,sa[i]));
ret+=num;
int preR=min(sa[i]+height[i]-,p);
num=upper_bound(v.begin(),v.end(),make_pair(sum[sa[i]]-,preR))-lower_bound(v.begin(),v.end(),make_pair(sum[sa[i]]-,sa[i]));
ret-=num;
}
printf("%I64d\n",ret);
}
}suf; int main() {
int n;
scanf("%d",&n);
scanf("%s",s);
sum[]=(s[]=='(')?:-;
for (int i=;i<n;i++)
sum[i]=sum[i-]+((s[i]=='(')?:-);
for (int i=;i<n;i++) {
v.push_back(make_pair(sum[i],i));
}
sort(v.begin(),v.end());
tab.setMin();
tab.init(n,sum);
suf.calcSA(s,n+,);
suf.calcHeight(s,n);
suf.solve(n);
return ;
}
CF IndiaHacks 2016 F Paper task 后缀数组的更多相关文章
- [CF653F] Paper task - 后缀数组,线段树,vector
[CF653F] Paper task Description 给定一个括号序列,统计合法的本质不同子串的个数. Solution 很容易想到,只要在传统统计本质不同子串的基础上修改一下即可. 考虑经 ...
- NOI 2016 优秀的拆分 (后缀数组+差分)
题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...
- 2016多校联合训练4 F - Substring 后缀数组
Description ?? is practicing his program skill, and now he is given a string, he has to calculate th ...
- 2016暑假多校联合---Substring(后缀数组)
2016暑假多校联合---Substring Problem Description ?? is practicing his program skill, and now he is given a ...
- CF 504E Misha and LCP on Tree(树链剖分+后缀数组)
题目链接:http://codeforces.com/problemset/problem/504/E 题意:给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. ...
- CF 504E Misha and LCP on Tree——后缀数组+树链剖分
题目:http://codeforces.com/contest/504/problem/E 树链剖分,把重链都接起来,且把每条重链的另一种方向的也都接上,在这个 2*n 的序列上跑后缀数组. 对于询 ...
- CF 504 E —— Misha and LCP on Tree —— 树剖+后缀数组
题目:http://codeforces.com/contest/504/problem/E 快速查询LCP,可以用后缀数组,但树上的字符串不是一个序列: 所以考虑转化成序列—— dfs 序! 普通的 ...
- CSU1656: Paper of FlyBrother(后缀数组)
Description FlyBrother is a superman, therefore he is always busy saving the world. To graduate fro ...
- CF(427D-Match & Catch)后缀数组应用
题意:给两个字符串,求一个最短的子串.使得这个子串在两个字符串中出现的次数都等于1.出现的定义为:能够重叠的出现. 解法:后缀数组的应用.从小枚举长度.假设一个长度len合法的话:则一定存在这个样的s ...
随机推荐
- JS入门(一)
在学js之前,我们应该先清楚js是什么,js全称JavaScript.是一门基于对象和事件的,有安全性的脚本语言.所谓脚本语言,就是一行一行执行的,就像剧本一样,一句句的往下读.而对象和事件,则是js ...
- python3.4 安装 scrapy 报错 VS2010
安装scrapy框架报错是常见问题 还好,本人只碰到其中一个bug,以下是此次安装经验 环境 py3.4 windows7 64位 安装有VS2010 pip包管理(pycharm) 报错信息 安装l ...
- swift -- as / 扩展
一.使用 可选链式 调用代替强制展开 //当声明一个属性时,将属性类型设置为可选类型: 好处: 当可选类型的属性被赋予初始值时,系统调用初始值;当可选类型属性没有赋予初始值时,系统只会调用失败;如果属 ...
- PHP数据访问易错点(20161030)
易错点: 1.造对象的时候括号里面的参数 写错了 $db = new MySQLi("localhost","root","789",&qu ...
- JDK中日期和时间的几个常用类浅析(三)
java.text.SimpleDateFormat SimpleDateFormat类是用于把字符串解析成日期时间和把日期时间格式化成字符串的工具类.该类主要和java.util.Date类配合 ...
- 解决在eclipse中写ImageView时有警告的问题
Eclipse中写了一个android程序其中main.xml中ImageView哪行是个黄叹号!不知道为什么? 解决办法: android:contentDescription="@str ...
- Java程序中与MongoDB建立连接~小记
1.Mongo和MongoClient的关系 MongoClient继承自Mongo,使用Mongo也可建立连接,但是需要使用与Mongo适应的MongoOptions,MongoURI等类型. 2. ...
- MySQL中的一些内置函数
mysql> select now(); #获取当前的日期和时间 +---------------------+ | now() | +---------------------+ | -- : ...
- java类的equals()函数和hashCode()函数用法
以前总觉得java类对象很简单,但是今天的一个同事的点播,让我对java的对象有了不一样的理解,下面我来介绍一下equals()和hashCode()的用法: 先粘一段代码: public class ...
- Java中类的继承,属性和方法的四种修饰符的作用范围,final关键字,java的三大特点中的2个:封装和多态,以及多态的一个设计模式,模板方法模式(template method)
(一)Java中的继承: 关于继承,在Java中类的继承只能是单继承,不像C+++那样灵活,可以多继承,多继承的后果就是各种关系乱套,就相当于一个孩子有2个母亲一样,社会关系的复杂,不利于程序后期的开 ...