题目链接

很容易想到p和q"r相似"就等价于在后缀数组中q与p之间的height值\(\ge r\),也就是说\(<r\)的那些height值会把排好序后的后缀分割成若干段,可以想到倒序枚举r,每当r减小1时,中间把他们分开的那些"屏障"就会减少一些,两边的集合会合并到一起,现在的问题就是给定一个集合,支持合并操作,每次询问元素乘积最大值(方案数显然是\(C_{siz}^2\))。由于有负值,只需记正值中最大的两个与负值中最小的两个即可。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<bitset>
#define P puts("lala")
#define cp cerr<<"lala"<<endl
#define ln putchar('\n')
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
inline int read()
{
char ch=getchar();int g=1,re=0;
while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
return re*g;
}
typedef long long ll;
typedef pair<int,int> pii; const int N=300050;
char s[N];
int n,Rank[N],tt2[N],sa[N],cnt[N],hei[N];
void buildsa()
{
int i,m=0,*x=Rank,*y=tt2;
for(i=1;i<=n;++i) cnt[x[i]=s[i]]++,m=max(x[i],m);
for(i=2;i<=m;++i) cnt[i]+=cnt[i-1];
for(i=n;i;--i) sa[cnt[x[i]]--]=i;
for(int k=1;k<n;k<<=1)
{
int p=0;
for(i=n-k+1;i<=n;++i) y[++p]=i;
for(i=1;i<=n;++i) if(sa[i]>k) y[++p]=sa[i]-k;
for(i=1;i<=m;++i) cnt[i]=0;
for(i=1;i<=n;++i) cnt[x[y[i]]]++;
for(i=2;i<=m;++i) cnt[i]+=cnt[i-1];
for(i=n;i;--i) sa[cnt[x[y[i]]]--]=y[i];
swap(x,y);
p=1; x[sa[1]]=1;
for(i=2;i<=n;++i) x[sa[i]]=y[sa[i-1]]==y[sa[i]]
&&y[sa[i-1]+k>n?0:sa[i-1]+k]==y[sa[i]+k>n?0:sa[i]+k]?p:++p;
m=p;
if(m>=n) break;
}
for(i=1;i<=n;++i) Rank[sa[i]]=i;
}
void buildheight()
{
int i,k=0;
for(i=1;i<=n;++i)
{
if(k) k--;
int j=sa[Rank[i]-1];
while(s[i+k]==s[j+k]) k++;
hei[Rank[i]]=k;
}
} struct dsynh
{
vector<int>neg,pos;
dsynh() {neg.clear();pos.clear();}
inline ll query()
{
if(neg.size()+pos.size()<=1) return 0;
ll ans=-3e18;
if(neg.size()==2) ans=max(ans,1ll*neg[0]*neg[1]);
if(pos.size()==2) ans=max(ans,1ll*pos[0]*pos[1]);
if(neg.size()&&pos.size()) ans=max(ans,1ll*neg[0]*pos[0]);
return ans;
}
inline void push(ll x)
{
if(x<0) neg.pb(x);
else pos.pb(x);
}
}t[N];
vector<int>ve[N];
int fa[N],siz[N];
inline int find(int x)
{
if(fa[x]!=x) return fa[x]=find(fa[x]);
return fa[x];
}
ll ans1=0;
ll merge(int x,int y)
{
x=find(x); y=find(y);
ans1-=(1ll*siz[x]*(siz[x]-1)/2+1ll*siz[y]*(siz[y]-1)/2);
fa[x]=y; siz[y]+=siz[x];
ans1+=1ll*siz[y]*(siz[y]-1)/2; for(int i=0;i<t[x].neg.size();++i) t[y].push(t[x].neg[i]);
for(int i=0;i<t[x].pos.size();++i) t[y].push(t[x].pos[i]);
t[x].neg.clear(); t[x].pos.clear(); sort(t[y].neg.begin(),t[y].neg.end(),greater<int>() );
while(t[y].neg.size()>2) t[y].neg.erase(t[y].neg.begin()); sort(t[y].pos.begin(),t[y].pos.end());
while(t[y].pos.size()>2) t[y].pos.erase(t[y].pos.begin());
return t[y].query();
} int val[N];
ll out1[N],out2[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);freopen("1.out","w",stdout);
#endif
int i,j,opt,T;
n=read();
scanf("%s",s+1);
for(i=1;i<=n;++i) val[i]=read();
buildsa(); buildheight(); for(i=2;i<=n;++i) ve[hei[i]].pb(i);
for(i=1;i<=n;++i) siz[i]=1,fa[i]=i,t[i].push(val[sa[i]]); ll ans2=-3e18;
for(int r=n-1;r>=0;--r)
{
int siz=ve[r].size();
for(i=0;i<siz;++i)
ans2=max(merge(ve[r][i]-1,ve[r][i]),ans2);
out1[r]=ans1; out2[r]=ans2==-3e18?0:ans2;
}
for(i=0;i<n;++i) printf("%lld %lld\n",out1[i],out2[i]);
return 0;
}

uoj131【NOI2015】品酒大会的更多相关文章

  1. BZOJ4199/UOJ131 [Noi2015]品酒大会

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  2. UOJ131 [NOI2015] 品酒大会

    考前挣扎(bu shi 之前留下来的坑 首先注意到 SAM的parent树 是反串的后缀树 也就是原串的前缀树 这个性质很重要 所以说我们在树上统计的时候两个点的lca就是两个后缀串的lcp 于是可以 ...

  3. BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]

    4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...

  4. [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  5. 洛谷 P2178 [NOI2015]品酒大会 解题报告

    P2178 [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和 ...

  6. 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

    [BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...

  7. [UOJ#131][BZOJ4199][NOI2015]品酒大会

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  8. BZOJ_4199_[Noi2015]品酒大会_后缀自动机

    BZOJ_4199_[Noi2015]品酒大会_后缀自动机 Description 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 酒家”和“首席 ...

  9. [NOI2015]品酒大会(SA数组)

    [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和" ...

  10. 洛谷P2178 [NOI2015]品酒大会 后缀数组+单调栈

    P2178 [NOI2015]品酒大会 题目链接 https://www.luogu.org/problemnew/show/P2178 题目描述 一年一度的"幻影阁夏日品酒大会" ...

随机推荐

  1. [spring]spring详细总结

    spring 1.spring简介 Spring框架是一个开源的应用程序框架,是针对bean的生命周期进行管理的轻量级容器. Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强 ...

  2. Python数据分析--Numpy常用函数介绍(9)-- 与线性代数有关的模块linalg

    numpy.linalg 模块包含线性代数的函数.使用这个模块,可以计算逆矩阵.求特征值.解线性方程组以及求解行列式等.一.计算逆矩阵 线性代数中,矩阵A与其逆矩阵A ^(-1)相乘后会得到一个单位矩 ...

  3. Python 车主之家全系车型(包含历史停售车型)配置参数爬虫

    本文仅供学习交流使用,如侵立删!demo下载见文末 车主之家全系车型(包含历史停售车型)配置参数爬虫 先上效果图 环境: win10 ,Contos7.4 python3.9.4 pycharm202 ...

  4. Linux使用netstat查看网络状态

    查看本机的网络状态.使用netstat查看网络状态.显示系统端口使用情况.UDP类型的端口.TCP类型的端口.只显示所有监听端口.只显示所有监听tcp端口. 命令使用举例 命令 说明 netstat ...

  5. Eclipse里项目名有红叉,但是项目里的每一个文件都没有红叉

    原因一:导入的文件被删除了. 解决方法:右击项目名,在弹出的菜单中,选择"Bulid Path"-->"configure build path"--&g ...

  6. java-前端之js

    js: js的三种形式: <!-- 事件:就是用户的操作或者动作,就是js被调用的时机:如:单机事件,双击事件 --> <!-- 1.事件定义式:在定义事件时直接写js --> ...

  7. Canvas 非线性图形(一):文本

    基础 画布除了绘制图形以外还可以绘制文本,画布中的文本可以设置字体大小.字体格式.对齐方式(横向和纵向对齐方式),并且还可以制作很炫酷的文本,比如渐变文字. 文本有以下三个属性,控制文本的字体大小.字 ...

  8. 【LOJ#3197】【eJOI2019】T形覆盖 - (图论、简单推导)

    题面 题解 (题目中说的四种摆放方式实际上是分别旋转0°,90°,180°,270°后的图形) 题目中关于摆放方式的描述听起来很臭,我们把它转换一下,每个拼版先覆盖"上下左右中"五 ...

  9. python数据精度问题

    一.python运算时精度问题: 1.运行时精度问题在Python中(其他语言中也存在这个问题,这是计算机采用二进制导致的),有时候由于二进制和十进制之间对应问题会导致数值的精度问题,比如无法用有限个 ...

  10. ak日记 831 dxm

    import sys from math import inf line = sys.stdin.readline().strip() vs = list(map(int, line.split()) ...