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 ...
随机推荐
- Hadoop 系统配置 map 100% reduce 0%
之前在本地配置了hadoop伪分布模式,hdfs用起来没问题,mapreduce的单机模式也没问题. 今天写了个程序,想在伪分布式上跑一下mapreduce,结果出现 map 100% reduce ...
- no module named firefly.master.master
因为没有安装firefly python setup.py install
- (转)Linux进程间通信
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 谢谢nonoob纠错 我们在Linux信号基础中已经说明,信号可以看作一种粗糙的进 ...
- JDBC 程序的常见错误及调试方法
详细介绍:http://dev.mysql.com/doc/refman/5.5/en/error-handling.html http://dev.mysql.com/doc/refman/5.5/ ...
- 使用var声明的变量 和 直接赋值并未声明的变量的区别
在看JS高级程序设计时忽然想到这个问题,众所周知,直接赋值一个变量而为声明,会产生一个全局变量(或者说是全局对象的属性),但用var声明的变量 和 直接赋值而并未声明的变量 都有哪些区别呢,这是我在百 ...
- 【poj2478-Farey Sequence】递推求欧拉函数-欧拉函数的几个性质和推论
http://poj.org/problem?id=2478 题意:给定一个数x,求<=x的数的欧拉函数值的和.(x<=10^6) 题解:数据范围比较大,像poj1248一样的做法是不可行 ...
- 8天学通MongoDB——第二天 细说增删查改
原文地址:http://www.cnblogs.com/huangxincheng/archive/2012/02/19/2357846.html 看过上一篇,相信大家都会知道如何开启mongodb了 ...
- ios开发多线程--GCD
引言 虽然GCD使用很广,而且在面试时也经常问与GCD相关的问题,但是我相信深入理解关于GCD知识的人肯定不多,大部分都是人云亦云,只是使用过GCD完成一些很简单的功能.当然,使用GCD完成一些简单的 ...
- CentOS7安装配置DNS服务器
准备工作(假设名称为bigcloud.local) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #更改主机名称 #vi /etc/sysconfig/netwo ...
- Docker基础技术:DeviceMapper
在上一篇介绍AUFS的文章中,大家可以看到,Docker的分层镜像是怎么通过UnionFS这种文件系统做到的,但是,因为Docker首选的AUFS并不在Linux的内核主干里,所以,对于非Ubuntu ...