COGS2217 papertask
以前看到这题的时候觉得是道好题啊……然而今天没多久就做出来了= =(装B
表示并没有看懂其他人写的是什么做法,感觉我的做法好奇怪……
我的做法是这样的:
首先给括号配对,不难发现所有括号串要么互不相交要么互相包含,也就是说它们形成了一个树形结构,暂且称之为括号树。
比如括号序列[[[][]][[[]][][]]]的括号树就是这样的:

每个节点的儿子就是剥掉最外层括号后的括号串,那么不难看出所有合法子串一定是某个节点的儿子顺序排列之后取连续的一段(必须是同一个节点的儿子,否则会因为最外层括号的缘故而使得子串不合法)。如果可以找到一种方法来区别本质不同的节点,那么直接把所有节点的儿子排列得到的字符串一块建一个广义后缀自动机就可以统计本质不同的子串个数了。最简单的方法就是利用哈希,然后就可以了……
注意这里的字符集可能很大,一开始觉得广义后缀自动机的复杂度是错的。后来才反应过来,所有字符串总长度只有n,因此建广义后缀自动机也还是线性的。
当然原串中连续的极长括号串也需要并在一起当作字符串插进去,这个稍微处理一下就行了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int maxn=;
const unsigned long long base=131ull;
void solve(int,int);
void insert(int*,int);
int expand(unsigned long long,int);
unsigned long long gethash(int,int);
int root,cnt=,val[maxn]={},par[maxn]={};
map<unsigned long long,int>go[maxn];
unsigned long long h[maxn],pw[maxn];
char str[maxn];
long long ans=;
int n,a[maxn],s[maxn],top,t[maxn],last=;
int main(){
freopen("papertask.in","r",stdin);
freopen("papertask.out","w",stdout);
int __size__=<<;
char *__p__=(char*)malloc(__size__)+__size__;
__asm__("movl %0, %%esp\n"::"r"(__p__));
root=++cnt;
scanf("%d",&n);
scanf("%s",str+);
pw[]=;
for(int i=;i<=n;i++)pw[i]=pw[i-]*base;
for(int i=n;i;i--)h[i]=h[i+]*base+str[i];
for(int i=;i<=n;i++){
if(str[i]=='(')s[++top]=i;
else{
if(!top)continue;
a[i]=s[top--];
a[a[i]]=i;
}
}
int x=,last=;
while(x<=n){
if(!a[x]){
x++;
continue;
}
last=x;
while(a[a[x]+])x=a[x]+;
solve(last,a[x]);
x=a[x]+;
}
printf("%lld\n",ans);
return ;
}
void solve(int l,int r){
if(l>r)return;
int cnt=,x=l;
while(x<=r){
t[cnt++]=gethash(x,a[x]-x+);
x=a[x]+;
}
insert(t,cnt);
x=l;
while(x<=r){
solve(x+,a[x]-);
x=a[x]+;
}
}
void insert(int *a,int n){
int x=root,i=;
//for(;i<n&&go[x].count(a[i]);i++)x=go[x][a[i]];
for(;i<n;i++)x=expand(a[i],x);
}
int expand(unsigned long long c,int p){
int np=++cnt;
val[np]=val[p]+;
while(p&&!go[p].count(c)){
go[p][c]=np;
p=par[p];
}
if(!p)par[np]=root;
else{
int q=go[p][c];
if(val[q]==val[p]+)par[np]=q;
else{
int nq=++cnt;
val[nq]=val[p]+;
go[nq]=go[q];
par[nq]=par[q];
par[np]=par[q]=nq;
while(p&&go[p][c]==q){
go[p][c]=nq;
p=par[p];
}
}
}
ans+=val[np]-val[par[np]];
return np;
}
inline unsigned long long gethash(int x,int l){return h[x]-h[x+l]*pw[l];}
COGS2217 papertask的更多相关文章
随机推荐
- Dubbo 自定义异常,你是怎么处理的?
前言 记录Dubbo对于自定义异常的处理方式. 实现目标 服务层异常,直接向上层抛出,web层统一捕获处理 如果是系统自定义异常,则返回{"code":xxx,"msg& ...
- SQL Full Join 的 Where条件
SQL需求是损益视图串资产负债视图 用Excel透视表模拟出来的结果就是 用SQL查询如下: 当Where条件是左边的视图的时候 select 损益视图.年 ,损益视图.年月 ,损益视图.期间 ,损益 ...
- windows jenkins 卸载
如果下载的是war包,先在任务管理器上停止jenkins的服务,再删除jenkins整个文件
- PXE+Kickstart 批量安装CentOS 7
安装之前 将需要安装 CentOS 的服务器与 PXE 服务器通过网络设备连接:PXE 服务器安装 CentOS,并且关闭firewalld.selinux,设置静态IP地址,本例设为10.0.0.1 ...
- 阿里云 下载的 apache 证书 转换为 pcks8 证书
第一步: 百度 搜索 rsa 转 pcks8 将 .key 文件 转换成 pcks8.key . 第二部: 将 chain.crt 的 内容 复制到 public.crt 下方.. 新的 publi ...
- 了解到的Web攻击技术
(1)XSS(Cross-Site Scripting,跨站脚本攻击): 指通过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或者JavaScript进行的一种攻击. (2)SQL注 ...
- #Go# 常用类型转换
#string 2 int int, err := strconv.Atoi(string) #string 2 int64 int64, err := strconv.ParseInt(string ...
- stark - 4 ⇲ 视图函数
✘ list_view 处理表格(默认是显示表结构的所有字段) 1 list_display = self.get_list_display() # 4.1处理表头 header_list = [] ...
- django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')
环境介绍 Django (2.1) Python 3.5.5 mysqlclient (1.4.2.post1) Mysql 5.6.28 RHEL 7.3 在migrate时候报错 model代码 ...
- 微信 oauth 登录 ,回调两次,一个坑,记录一下。
在做微信某个功能的时候,大致需求是:静默授权,得到openId ,然后拿着openId调用接口,判断是否关注.如果是关注的,则发放礼券.每个我网站的会员只会发放一次礼券.如果第二次则会提示已领取过礼券 ...