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 ...
随机推荐
- input输入框的border-radius属性在IE8下的完美兼容
在工作中我们发现搜索框大部分都是有圆角的,为此作为经验不足的前端人员很容易就想到,给input标签添加border-radius属性不就解决了嘛.不错方法确实是这样,但是不要忘了border-radi ...
- mongodb 主从服务器
@set mongod=..\bin\mongod.exe set keyFile=key.key if not exist %keyFile% ( echo 123456>%keyFile% ...
- CKEditor (Toolbar Definition)工具栏自定义配置
JS是大小写敏感的, 在设置配置文件的时候需要注意 以CKEditor 4为基础我们可以通过两种方式配置CKEditor的工具栏,一种是是通过config.js配置文件设置, 另一种是IN-PAGE方 ...
- 浅谈 OneAPM 在 express 项目中的实践
[编者按]OneAPM 运营团队,近日在 github 上发现了一篇文章,特别奉献给大家.本文作者王宇先生从2015年年初就开始使用我们的产品,也是OneAPM 的忠实用户. OneAPM 是一个优秀 ...
- 刘汝佳 算法竞赛-入门经典 第二部分 算法篇 第五章 3(Sorting/Searching)
第一题:340 - Master-Mind Hints UVA:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Item ...
- 从xml文件中读取注释
void Main() { string dirp=@"E:\Cread\UP4201308.bak\UP4.BAK\ExportPath\ConfigFile\"; ...
- node操作mysql数据库
1.建立数据库连接:createConnection(Object)方法 该方法接受一个对象作为参数,该对象有四个常用的属性host,user,password,database.与php ...
- Spark基础与Java Api介绍
原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3832405.html 一.Spark简介 1.什么是Spark 发源于AMPLab实验室的分布式内存计 ...
- HTML基本操作
插入图片: 1.利用链接(静态) <img src="http://www.kmwzjs.com/useruploads/images/20101020_057600100825157 ...
- ubuntu系统使用minicom终端操作说明
http://blog.chinaunix.net/uid-22030783-id-3350834.html 在linux下,使用minicom作为串口终端工具,默认的串口设备是/dev/ttyS0, ...