题面:

传送门

分析:

此题O(n2l)" role="presentation" style="position: relative;">O(n2l)O(n2l)模拟肯定是会超时的(l为所有字符串总长)

我们想到对字符串进行一定的预处理,可以快速计算匹配

我们设每一个(的值为1,)的值为-1,规定

若只有)括号多了x个,则l[i]=r[i]=-x<0

若只有(括号多了x个,则l[i]=r[i]=x>0

那么如何求l[i],r[i]的值呢?

从左到右扫描字符串,用一个变量cnt,统计和

cnt的最小值=l[i],最终的值=r[i]

若(和)都有多余,则必须接两个字符串,不符合条件,所以计算时应该直接跳过这些字符串,不用考虑

要理解这句话,请看下面的模拟过程

)()

字符串下标(0开始) 0 1 2

cnt值 -1 0 -1

l[i]=-1,说明左边需要一个(括号来匹配 (>=0即不需要)

r[i]=-1,说明右边不需要(<=0即不需要),而左边需要一个(括号

我们以all[i]来hash,哈希表的第 x位存储了所有r[i]=x的字符串的l[i]

但要注意的是,由于负数的原因,数组下标要人为加上一个数addv来存储

为了防止一对字符串被算两次,我们规定字符串只能接在右边,我们枚举字符串时要先保证l[i]>=0才能接,而l[i]<0的只能接在其他字符串右边

对于一个l[i]>=0的字符串i,我们寻找接在它右侧能匹配的字符串,所以我们在哈希表的−r[i]" role="presentation" style="position: relative;">−r[i]−r[i]位置寻找l[i]值为−r[i]" role="presentation" style="position: relative;">−r[i]−r[i]的字符串

比如:()(的l[i]=0,r[i]=1,我们则要寻找r[i]=l[i]=-1,即只多了一个)括号的字符串

用二分查找统计值为−r[i]" role="presentation" style="position: relative;">−r[i]−r[i]的字符串的个数,答案+=值为−r[i]" role="presentation" style="position: relative;">−r[i]−r[i]的字符串的个数

预处理时间复杂度O(l)" role="presentation" style="position: relative;">O(l)O(l) (l为所有字符串总长)

二分查找时间复杂度O(nlog2l)" role="presentation" style="position: relative;">O(nlog2l)O(nlog2l)

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define addv 300005
#define maxn 2*addv
using namespace std;
int n;
char str[maxn];
int cnt;
int l[maxn];
int r[maxn];
vector<int>table[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",str);
int len=strlen(str);
l[i]=maxn;
cnt=0;
for(int j=0;j<len;j++){//像分析中一样求l[i],r[i]
if(str[j]=='(') cnt++;
else cnt--;
l[i]=min(l[i],cnt);
}
r[i]=cnt;
table[r[i]+addv].push_back(l[i]);//hash,为了防止负数人为加上addv,addv就相当于新的零点
}
for(int i=1;i<maxn;i++) if(table[i].size()!=0) sort(table[i].begin(),table[i].end());//排序,为了二分查找
long long ans=0;
for(int i=1;i<=n;i++){
if(l[i]>=0){
int tmp=addv-r[i];//即-r[i]
ans+=table[tmp].end()-lower_bound(table[tmp].begin(),table[tmp].end(),-r[i]);//lower_bound返回第一个>=x的位置,用结尾去-它,可求出l[j]=r[j]=-r[i]的j的个数
}
}
printf("%I64d\n",ans);
}

最新文章

  1. 【SQL语句】update ... ... from ......
  2. Protocol buffers 介绍
  3. Spring学习笔记—最小化Spring XML配置
  4. Linux 的字符串截取方法(转)
  5. [原创]java WEB学习笔记67:Struts2 学习之路-- 类型转换概述, 类型转换错误修改,如何自定义类型转换器
  6. 年轻的团队Mono玩转Dalvik
  7. 防止vuejs在解析时出现闪烁
  8. Libcurl笔记三
  9. C语言碰到的一元二次方程
  10. PHP环境配置综合篇
  11. 关于T-SQL重编译那点事,内联函数和表值函数在编译生成执行计划的区别
  12. 使用yii2实现读写分离(MySQL主从数据库)
  13. java序列化浅谈
  14. jQuery的下拉选select2插件用法
  15. Xgboost总结
  16. 浅谈ASP.NET框架
  17. 15.scrapy中selenium的应用
  18. 指向函数的指针 ------ 函数指针(function pointer)
  19. ionic build - 修改gradle路径提升速度和成功率
  20. 数据结构与算法之PHP实现队列、栈

热门文章

  1. Laya 使list渲染支持分帧的思路
  2. 一、Nginx常见问题
  3. 「JOISC 2016 Day 3」回转寿司
  4. UOJ428. 【集训队作业2018】普通的计数题
  5. C++中一些容易迷惑的语法点总结
  6. Laravel5.5执行 npm run dev时报错,提示cross-env找不到(not found)的解决办法
  7. 织梦dedecms发布视频文章前台变成一张图片的解决方法
  8. 十、补充数据类型set
  9. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_05 List集合_1_List集合_介绍&amp;常用方法
  10. abstract 和 interface 抽象类和接口的区别