题目链接: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 后缀数组的更多相关文章

  1. [CF653F] Paper task - 后缀数组,线段树,vector

    [CF653F] Paper task Description 给定一个括号序列,统计合法的本质不同子串的个数. Solution 很容易想到,只要在传统统计本质不同子串的基础上修改一下即可. 考虑经 ...

  2. NOI 2016 优秀的拆分 (后缀数组+差分)

    题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...

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

    Description ?? is practicing his program skill, and now he is given a string, he has to calculate th ...

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

    2016暑假多校联合---Substring Problem Description ?? is practicing his program skill, and now he is given a ...

  5. CF 504E Misha and LCP on Tree(树链剖分+后缀数组)

    题目链接:http://codeforces.com/problemset/problem/504/E 题意:给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. ...

  6. CF 504E Misha and LCP on Tree——后缀数组+树链剖分

    题目:http://codeforces.com/contest/504/problem/E 树链剖分,把重链都接起来,且把每条重链的另一种方向的也都接上,在这个 2*n 的序列上跑后缀数组. 对于询 ...

  7. CF 504 E —— Misha and LCP on Tree —— 树剖+后缀数组

    题目:http://codeforces.com/contest/504/problem/E 快速查询LCP,可以用后缀数组,但树上的字符串不是一个序列: 所以考虑转化成序列—— dfs 序! 普通的 ...

  8. CSU1656: Paper of FlyBrother(后缀数组)

    Description FlyBrother is a superman, therefore he is always busy saving the world.  To graduate fro ...

  9. CF(427D-Match &amp; Catch)后缀数组应用

    题意:给两个字符串,求一个最短的子串.使得这个子串在两个字符串中出现的次数都等于1.出现的定义为:能够重叠的出现. 解法:后缀数组的应用.从小枚举长度.假设一个长度len合法的话:则一定存在这个样的s ...

随机推荐

  1. visibility: hidden和 display: none的区别

    visibility: hidden----将元素隐藏,但是在网页中该占的位置还是占着. display: none----将元素的显示设为无,即在网页中不占任何的位置.

  2. Java反射机制深度剖析

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! Java反射机制是Java语言中一种很重要的机制,可能在工作中用到的机会不多,但是在很多框架中都有用到这种机制.我们知道Java是一门静态 ...

  3. scrapy学习笔记

    1.scrapy用哪条命令行重新编辑已有的项目?cd projectname 2.如何在pycharm中开启scrapy?先在终端创建一个项目(即文件夹),再在pycharm中打开.

  4. 用Angular2+Express快速搭建博客

    1. 写在前面 昨天花了1天的时间把自己的博客从以前的Express换成了Angular2+Express,遂记录于此.博客Demo在这里,你也可以点击这里查看完整代码. 第一次使用Angular2, ...

  5. js高程(二)-----继承

    首先来讨论一下原型链,上代码 function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = fun ...

  6. Linux中的sed命令

    sed - stream editor for filtering and transforming text 流编辑器的过滤和转换文本 sed [-nerf] [动作] 参数: -i 修改源文件 危 ...

  7. 基于CDIF实现的——API在线自动化测试

    传统的测试工具在测试一个API的时候,必须手动填写这个API所需要接收的所有信息,比如一个查询航班动态的API,他接收两个输入字段,一个叫flight, 一个叫date,那么测试这个API的用户,需要 ...

  8. Mybatis 中一对多,多对一的配置

    现在有很多电商平台,就拿这个来说吧.顾客跟订单的关系,一个顾客可以有多张订单,但是一个订单只能对应一个顾客. 一对多的顾客 <?xml version="1.0" encod ...

  9. EDP转接IC NCS8805:RGB/LVDS转EDP芯片,带Scaler

    RGB/LVDS-to-eDP Converter w/ Scaler1 FeaturesEmbedded-DisplayPort (eDP) Output1/2/4-lane eDP @ 1.62/ ...

  10. Uva 10006 Carmichael Numbers (快速幂)

    题意:给你一个数,让你判断是否是非素数,同时a^n%n==a (其中 a 的范围为 2~n-1) 思路:先判断是不是非素数,然后利用快速幂对每个a进行判断 代码: #include <iostr ...