bzoj4199
看到这题我就伤心,当初想到了正解却因为各种sb原因没有写……
好吧,其实我的正解是比较挫的……
大家似乎都用了后缀数组,我用了后缀自动机(后缀树)
其实SAM是很好想得,用SAM建出后缀树后
我们考虑树上每个节点对答案的贡献,0相似就不必说了
考虑到任意两个后缀的LCP即这两个后缀所在节点的LCA的节点所能接受的最长子串mx[i]
又每个节点能接收的子串长度为[mx[fa[i]]+1,mx[i]]
我们很容易想出问题1:设节点i的子树内代表后缀的节点个数为s,那么节点i对区间[mx[fa[i]]+1,mx[i]]贡献是s*(s-1)/2
问题2:很显然找出节点i子树内max{最大*次大,最小*次小}(因为有负数),这要dfs序+线段树维护,然后区间覆盖再来个线段树……
总复杂度是O(nlogn),实际是能过的(但是跑得似乎比SA做法慢……)
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<stdlib.h>
#define ll long long
#define N 300005
using namespace std;
const ll inf=-;
const ll small=-1000000002000000001ll;
int go[*N][],fa[*N],w[*N],mx[*N],p[*N],a[*N],b[*N],l[*N],r[*N];
struct node{ll b1,b2,s1,s2;} tree[*N];
struct way{int po,next;} e[*N];
ll ans[*N][];
int n,last,t,len;
char s[N]; void ins(int x,int y)
{
e[++len].po=y;
e[len].next=p[x];
p[x]=len;
} void add(int c,int x)
{
int np,nq,q,p=last;
np=++t; mx[np]=mx[p]+; a[np]=x; w[np]=;
for (;p&&!go[p][c];p=fa[p]) go[p][c]=np;
if (!p) fa[np]=;
else {
q=go[p][c];
if (mx[q]==mx[p]+) fa[np]=q;
else {
nq=++t; a[t]=inf;
mx[nq]=mx[p]+;
memcpy(go[nq],go[q],sizeof(go[q]));
fa[nq]=fa[q]; fa[np]=fa[q]=nq;
for (;go[p][c]==q;p=fa[p]) go[p][c]=nq;
}
}
last=go[last][c];
} void dfs(int x)
{
l[x]=++t; b[t]=x;
for (int i=p[x];i;i=e[i].next)
{
int y=e[i].po;
dfs(y); w[x]+=w[y];
}
r[x]=t;
} void update(node &a,node x,node y)
{
if (x.b1>y.b1)
{
a.b1=x.b1;
a.b2=max(x.b2,y.b1);
}
else {
a.b1=y.b1;
a.b2=max(x.b1,y.b2);
}
if (x.s1>y.s1)
{
a.s1=y.s1;
a.s2=min(x.s1,y.s2);
}
else {
a.s1=x.s1;
a.s2=min(x.s2,y.s1);
}
}
void build(int i,int l, int r)
{
if (l==r)
{
tree[i].b1=a[b[l]];
tree[i].b2=inf;
tree[i].s2=-inf;
tree[i].s1=(a[b[l]]==inf)?-inf:a[b[l]];
return;
}
int m=(l+r)>>;
build(i*,l,m);
build(i*+,m+,r);
update(tree[i],tree[i*],tree[i*+]);
} node get(int i,int l,int r,int x, int y)
{
if (x<=l&&y>=r) return tree[i];
int m=(l+r)>>;
node s,b,c;
b.b1=b.b2=c.b1=c.b2=inf;
b.s1=b.s2=c.s1=c.s2=-inf;
if (x<=m) b=get(i*,l,m,x,y);
if (y>m) c=get(i*+,m+,r,x,y);
update(s,b,c);
return s;
} void work(int i,int l,int r,int x,int y,ll a,ll b)
{
if (x<=l&&y>=r) {ans[i][]+=a; ans[i][]=max(ans[i][],b);}
else {
int m=(l+r)>>;
if (ans[i][])
{
ans[i*][]+=ans[i][]; ans[i*+][]+=ans[i][];
ans[i][]=;
}
if (ans[i][]>small)
{
ans[i*][]=max(ans[i][],ans[i*][]); ans[i*+][]=max(ans[i][],ans[i*+][]);
ans[i][]=small;
}
if (x<=m) work(i*,l,m,x,y,a,b);
if (y>m) work(i*+,m+,r,x,y,a,b);
}
} void getans(int i,int l,int r)
{
if (l==r)
{
if (ans[i][]==) ans[i][]=;
printf("%lld %lld\n",ans[i][],ans[i][]);
}
else {
int m=(l+r)>>;
if (ans[i][]>small) {ans[i*][]=max(ans[i][],ans[i*][]); ans[i*+][]=max(ans[i][],ans[i*+][]);}
if (ans[i][]) {ans[i*][]+=ans[i][]; ans[i*+][]+=ans[i][];}
getans(i*,l,m);
getans(i*+,m+,r);
}
} int main()
{
scanf("%d",&n); scanf("%s",s+);
for (int i=; i<=n; i++) scanf("%d",&b[i]);
if (n==) {puts("0 0");return ;}
t=last=; a[]=inf;
for (int i=n;i;i--) add(s[i]-'a',b[i]);
for (int i=;i<=t; i++) ins(fa[i],i);
t=; dfs();
build(,,t);
for (int i=; i<=n*;i++) ans[i][]=small;
for (int i=; i<=t; i++)
{
if (w[i]<=) continue;
node c=get(,,t,l[i],r[i]);
ll x=max(c.b1*c.b2,c.s1*c.s2);
work(,,n-,mx[fa[i]]+,mx[i],(ll)(w[i]-)*(ll)(w[i])/,x);
}
printf("%lld %lld\n",(ll)(w[]-)*(ll)(w[])/,max(tree[].b1*tree[].b2,tree[].s1*tree[].s2));
getans(,,n-);
return ;
}
bzoj4199的更多相关文章
- [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- 【BZOJ4199】【NOI2015】品酒大会(后缀数组)
[BZOJ4199][NOI2015]品酒大会 题面 BZOJ Uoj 洛谷 题解 考虑最裸的暴力 枚举每次的长度 以及两个开始的位置 检查以下是否满足条件,如果可以直接更新答案 复杂度\(O(n^3 ...
- Bzoj4199:[NOI2015]品酒大会
题面 Bzoj4199 Sol 后缀数组 显然的暴力就是求\(LCP\)+差分 \(40\)分 # include <bits/stdc++.h> # define RG register ...
- 【bzoj4199】【Noi2015】品酒大会
题解 SA+并查集 把ht按大小倒序加入,并查集合并维护答案的变化: SAM 翻转串,求出SAM的parent树就是后缀树,两个串的最长公共后缀是他们lca的len值: 考率一个节点x,那么它子树里的 ...
- 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集
[BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp
品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...
- 【BZOJ4199&UOJ131】品酒大会(后缀数组,并查集)
题意: 两杯“r相似” (r>1)的酒同时也是“1 相似”.“2 相似”.…….“(r−1) 相似”的. n<=300000 abs(a[i])<=10^9 思路:对于i,j两个后缀 ...
- [BZOJ4199][NOI2015]品酒大会
#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...
- bzoj4199:NOI2015D2T2品酒大会(SAM版)
SAM感觉写起来比SA更直观(?) #include <iostream> #include <cstdio> #include <cstring> #includ ...
随机推荐
- ios 设计软件
briefs V1.0.5 download @ here:http://soft.macx.cn/5442.htm 密码:www.macx.cn
- HDU4831&&4832&&4834
好久没打代码啦,今天lu一发百度之星,感觉还是学到不少东西的,写点收获. 第一题就是现在的HDU4831啦,题意很清楚,我一开始以为休息区也可以变为风景区,所以就不敢敲了,后来才得知数据里只会改风景区 ...
- 编程实现Linux下的ls -l
头文件 #ifndef __FUNC_H__ #define __FUNC_H__ #include <stdio.h> #include <stdlib.h> #includ ...
- 【android原生应用】之闹钟应用搭起篇
由于工作原因接触android开发一段时间了,对于开发有了一些了解,于是萌生了搭起android原生应用进行分析和学习的想法.先从闹钟应用开始吧. 1.首先要下载原生应用,原生应用在原生系统里面(当然 ...
- iOS开发--3D Touch的基本使用
1.桌面快捷菜单项 效果如图: 桌面快捷菜单 点击之后的效果如图: 点击桌面快捷菜单的效果 接下来看下具体实现:1).在-application:didFinishLaunchingWithOptio ...
- IOS底层数据结构--class
一.类的数据结构 Class(指针) typedef struct objc_class *Class; /* 这是由编译器为每个类产生的数据结构,这个结构定义了一个类.这个结构是通过编译器在执行时产 ...
- MyBatis学习总结_02_使用MyBatis对表执行CRUD操作
一.使用MyBatis对表执行CRUD操作——基于XML的实现 1.定义sql映射xml文件 userMapper.xml文件的内容如下: 1 <?xml version="1.0&q ...
- C++:异常的处理
6.4 异常处理 程序中常见的错误分为两大类:编译时期的错误和运行时期的错误. 编译时期的错误比较简单容易发现:主要是语法错误,如关键字拼写错误.缺分号.括号不匹配等 运行时期的错误比较难发现,甚至是 ...
- .NET单例模式-------各种写法&&验证
.NET单例模式-------各种写法&&验证 前言 单例模式对大家来说都不陌生,也很容易搞懂其原理,本篇文章也不提供单例模式的详细原理解析,本篇文章的目的是展示在C#中单例模式的各种 ...
- android-HttpClient上传信息(包括图片)到服务端
需要下载apache公司下的HttpComponents项目下的HTTPCLIENT ----------地址为http://hc.apache.org/downloads.cgi 主要是用到了htt ...