Bzoj4199:[NOI2015]品酒大会
题面
Sol
后缀数组
显然的暴力就是求\(LCP\)+差分
\(40\)分
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(3e5 + 5);
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int a[_], n, s[_], rk[_], sa[_], height[_], tmp[_], t[_];
ll ans1[_], ans2[_];
int st[20][_], lg[_];
char ss[_];
IL int Cmp(RG int i, RG int j, RG int k){
return tmp[i] == tmp[j] && i + k <= n && j + k <= n && tmp[i + k] == tmp[j + k];
}
IL void Suffix_Sort(){
RG int m = 26;
for(RG int i = 1; i <= n; ++i) ++t[rk[i] = s[i]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[i]]--] = i;
for(RG int k = 1; k <= n; k <<= 1){
RG int l = 0;
for(RG int i = n - k + 1; i <= n; ++i) tmp[++l] = i;
for(RG int i = 1; i <= n; ++i) if(sa[i] > k) tmp[++l] = sa[i] - k;
for(RG int i = 0; i <= m; ++i) t[i] = 0;
for(RG int i = 1; i <= n; ++i) ++t[rk[tmp[i]]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[tmp[i]]]--] = tmp[i];
swap(tmp, rk), rk[sa[1]] = l = 1;
for(RG int i = 2; i <= n; ++i) rk[sa[i]] = Cmp(sa[i - 1], sa[i], k) ? l : ++l;
if(l >= n) break;
m = l;
}
for(RG int i = 1, h = 0; i <= n; ++i){
if(h) --h;
while(s[i + h] == s[sa[rk[i] - 1] + h]) ++h;
height[rk[i]] = h;
}
}
IL void ST_Prepare(){
for(RG int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
for(RG int i = 1; i <= n; ++i) st[0][i] = height[i];
for(RG int i = 1; i <= lg[n]; ++i)
for(RG int j = 1; j + (1 << i) - 1 <= n; ++j)
st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
}
IL int LCP(RG int x, RG int y){
x = rk[x], y = rk[y];
if(x > y) swap(x, y); ++x;
RG int len = y - x + 1;
return min(st[lg[len]][x], st[lg[len]][y - (1 << lg[len]) + 1]);
}
int main(RG int argc, RG char* argv[]){
Fill(ans2, -127), n = Input(), scanf(" %s", ss + 1);
for(RG int i = 1; i <= n; ++i) s[i] = ss[i] - 'a' + 1, a[i] = Input();
Suffix_Sort(), ST_Prepare();
for(RG int i = 1; i < n; ++i)
for(RG int j = i + 1; j <= n; ++j){
RG int lcp = LCP(i, j);
++ans1[0], --ans1[lcp + 1];
ans2[lcp] = max(ans2[lcp], 1LL * a[i] * a[j]);
}
for(RG int i = 0; i < n; ++i) ans1[i] += ans1[i - 1];
for(RG int i = n - 1; ~i; --i) ans2[i] = max(ans2[i], ans2[i + 1]);
for(RG int i = 0; i < n; ++i) printf("%lld %lld\n", ans1[i], ans2[i] == ans2[n] ? 0 : ans2[i]);
return 0;
}
正解,把\(height\)从大到小排序
每次合并\(height\)两边的集合,因为从大到小,所以两边集合的\(LCP\)一定就是这个\(height\),因为有负数权值,维护集合的最大值,最小值组合
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(3e5 + 5);
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int a[_], n, s[_], rk[_], sa[_], height[_], tmp[_], t[_];
ll ans1[_], ans2[_];
int fa[_], id[_], size[_], mx[_], mn[_];
char ss[_];
IL int Cmp(RG int i, RG int j, RG int k){
return tmp[i] == tmp[j] && i + k <= n && j + k <= n && tmp[i + k] == tmp[j + k];
}
IL int _Cmp(RG int x, RG int y){
return height[x] > height[y];
}
IL void Suffix_Sort(){
RG int m = 26;
for(RG int i = 1; i <= n; ++i) ++t[rk[i] = s[i]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[i]]--] = i;
for(RG int k = 1; k <= n; k <<= 1){
RG int l = 0;
for(RG int i = n - k + 1; i <= n; ++i) tmp[++l] = i;
for(RG int i = 1; i <= n; ++i) if(sa[i] > k) tmp[++l] = sa[i] - k;
for(RG int i = 0; i <= m; ++i) t[i] = 0;
for(RG int i = 1; i <= n; ++i) ++t[rk[tmp[i]]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[tmp[i]]]--] = tmp[i];
swap(tmp, rk), rk[sa[1]] = l = 1;
for(RG int i = 2; i <= n; ++i) rk[sa[i]] = Cmp(sa[i - 1], sa[i], k) ? l : ++l;
if(l >= n) break;
m = l;
}
for(RG int i = 1, h = 0; i <= n; ++i){
if(h) --h;
while(s[i + h] == s[sa[rk[i] - 1] + h]) ++h;
height[rk[i]] = h;
}
}
IL int Find(RG int x){
return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
int main(RG int argc, RG char* argv[]){
Fill(ans2, -127), n = Input(), scanf(" %s", ss + 1);
for(RG int i = 1; i <= n; ++i) s[i] = ss[i] - 'a' + 1, a[i] = Input();
for(RG int i = 1; i <= n; ++i) fa[i] = id[i] = i, size[i] = 1, mx[i] = mn[i] = a[i];
Suffix_Sort(), sort(id + 2, id + n + 1, _Cmp);
for(RG int i = 2; i <= n; ++i){
RG int fx = Find(sa[id[i] - 1]), fy = Find(sa[id[i]]);
ans1[height[id[i]]] += 1LL * size[fx] * size[fy];
fa[fy] = fx, size[fx] += size[fy];
ans2[height[id[i]]] = max(ans2[height[id[i]]], max(1LL * mx[fx] * mx[fy], 1LL * mx[fx] * mn[fy]));
ans2[height[id[i]]] = max(ans2[height[id[i]]], max(1LL * mn[fx] * mx[fy], 1LL * mn[fx] * mn[fy]));
mx[fx] = max(mx[fx], mx[fy]);
mn[fx] = min(mn[fx], mn[fy]);
}
for(RG int i = n - 1; ~i; --i) ans1[i] += ans1[i + 1], ans2[i] = max(ans2[i], ans2[i + 1]);
for(RG int i = 0; i < n; ++i) printf("%lld %lld\n", ans1[i], ans2[i] == ans2[n] ? 0 : ans2[i]);
return 0;
}
Bzoj4199:[NOI2015]品酒大会的更多相关文章
- [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp
品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...
- [BZOJ4199][NOI2015]品酒大会
#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...
- bzoj4199: [Noi2015]品酒大会(后缀数组)
题目描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainb ...
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
- 并不对劲的bzoj4199: [Noi2015]品酒大会
传送门-> 又称普及大会. 这题没什么好说的……后缀自动机裸题……并不对劲的人太菜了,之前照着标程逐行比对才过了这道题,前几天刚刚把这题一遍写对…… 这题的输出和某两点相同后缀的长度有关,那么把 ...
- 2019.02.28 bzoj4199: [Noi2015]品酒大会(sam+线段树)
传送门 题意:给一个串,每个位置有一个权值,当S[s...s+len−1]=S[t...t+len−1]&&S[s...s+len]̸=S[t..t+len]S[s...s+len-1 ...
- bzoj千题计划257:bzoj4199: [Noi2015]品酒大会
http://www.lydsy.com/JudgeOnline/problem.php?id=4199 求出后缀数组的height 从大到小枚举,合并 维护组内 元素个数,最大.次大.最小.次小 # ...
- [BZOJ4199][Noi2015]品酒大会 树形DP+后缀自动机
由于要找后缀的前缀,所以先用反串建立SAM. link边组成了后缀树. 两个子串的最长公共前缀是LCA的step 树形dp即可. #include<iostream> #include&l ...
随机推荐
- 百度编辑器Ueditor增加字体的修改方法
http://www.jb51.net/article/109896.htm Ueditor本身自带11种字体 使用过程中这11种字体往往不能满足我们的需求,现在我要添加"仿宋" ...
- docker设置固定ip地址
Docker安装后,默认会创建下面三种网络类型 $ docker network ls NETWORK ID NAME DRIVER SCOPE 9781b1f585ae bridge bridge ...
- git 域名配置
在Godaddy购买的域名: 查找DNSpod解析域名,没什么难度,就是添加一条记录,保存而已,记得在添加域名到DNSpod之后,复制两个NS地址到godaddy的域名服务器下: Git项目根目录下创 ...
- ARM平台的虚拟化介绍
本篇博文主要介绍虚拟化的基本思想以及在arm平台如何做虚拟化,arm提供的硬件feature等等. 虚拟化技术简介 虚拟化技术 虚拟化是一个概念,单从这个概念的角度来看,只要是用某一种物品去模拟另一种 ...
- LNMP安装后MYSQL数据库无法远程访问解决
解决思路: 之前也遇到过这个问题,解决的途径也是五花八门,从百度和Google上也看到各种解决方案,基本上分以下几种: 没有给root对应的权限 -- @'192.168.1.123'可以替换为@'% ...
- SpringBoot Hello World
本文首发于我的github博客 前言 SpringBoot是Spring MVC升级版,基于『约定优于配置』的原则,快速开发出web程序. 环境 本系列笔记环境如下: Sun JDK1.8.0_20 ...
- 1.4 random模块
Python中的random模块用于生成随机数,下面介绍一下random模块中最常用的几个函数. 国际惯例,用模块之前先导入: >>> import random (一)random ...
- 3.数码相框-通过freetype库实现矢量显示
本章主要内容如下: 1)矢量字体原理 2)使用freetype库实现矢量字体显示 1. 矢量字体原理 将汉字的笔划边缘用直线段描述成封闭的曲线,并将线段各端点的坐标经压缩存储,如下图所示: 由于每个汉 ...
- scrapy的学习总结(1)
1.xpath和css的节点的共同结合使用是一个挺好的使用过程,还有就是配合正则表达式的使用,这个也是很重要的.解决任何一个问题都会有不同方法.学会思考的解决问题. 2.item的数据抽取,pipel ...
- linux查看端口被占用等常用命令
一 根据端口号 查找对应的服务 比如我们查查找端口号8189对应的服务是哪个 1 先根据端口号查找对应对的pid(进程id)为23367 netstat -anp | grep 8189 ...