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 ...
随机推荐
- http authorization basic请求代码示例
/** * */ package testJava.java; import java.io.BufferedReader; import java.io.InputStream; import ja ...
- docker-py的配置与使用
测试环境 75机:Red Hat Enterprise Linux Server 7.0,无外网访问权限 73机:Red Hat Enterprise Linux Server 7.0,无外网访问权限 ...
- delphi 中几种多线程操作方式
在了解多线程之前我们先了解一下进程和线程的关系 一个程序至少有一个主进程,一个进程至少有一个线程. 为了保证线程的安全性请大家看看下面介绍 Delphi多线程同步的一些处理方案大家可以参考:http: ...
- Codeforces446C DZY Loves Fibonacci Numbers(线段树 or 分块?)
第一次看到段更斐波那契数列的,整个人都不会好了.事后看了题解才明白了一些. 首先利用二次剩余的知识,以及一些数列递推式子有下面的 至于怎么解出x^2==5(mod 10^9+9),我就不知道了,但是要 ...
- ZOJ 3555 Ice Climber(dp)
晦涩的题意+各种傻逼害我调了那么久,实际上题目就是一个dp[i][j],dp[i][j]表示第i层第j个最少需要多少时间,当我们去更新dp[i][j]的时候,考虑的是从第i+1层的某一个dp[i+1] ...
- Javascript offsetLeft详情
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- MySQL: InnoDB 还是 MyISAM? (转载)
MyISAM存储引擎 原文作者:http://www.cnblogs.com/villion/archive/2009/07/09/1893762.html MyISAM是 默认存储引擎.它基于更老的 ...
- hdu 1404/zoj 2725 Digital Deletions 博弈论
暴力打表!! 代码如下: #include<iostream> #include<algorithm> #include<cstdio> #include<c ...
- Node 出现 uncaughtException 之后的优雅退出方案
Node 的异步特性是它最大的魅力,但是在带来便利的同时也带来了不少麻烦和坑,错误捕获就是一个.由于 Node 的异步特性,导致我们无法使用 try/catch 来捕获回调函数中的异常,例如: try ...
- Xamarin.Android MVP模式
一.简介 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数 据的可视化以及与用户的交互,同时让Model只 ...