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 ...
随机推荐
- LearnPython_week2
1. 列表.元组 2. 字典 3. 集合 4. 字符串的各种姿势 5. OPEN文件操作 1. 列表.元组 列表 names = ['wong','caiyun',' ...
- Git团队协作之GitFlow & SoucceTree
GitFlow 定义了一个围绕项目发布的严格的分支模型,仍然使用中央仓库作为开发者的交互中心 GitFlow分支 Master分支 Hotfix紧急修改 Release分支 Develop开发分支 F ...
- TJ4运行环境
http://springwq2011.blog.51cto.com/4332889/966028 http://blog.csdn.net/u013573789/article/details/45 ...
- angular2^ typescript 将 文件和Json数据 合并发送到服务器(1.客户端处理)
首先介绍下框架基本流程 (web > webservice [前端架构] ) > (nodejs [ 数据中转站 ]) >(api [后台接口]) --web (html a ...
- 深入java虚拟机学习 -- 类的加载机制
当看到"类的加载机制",肯定很多人都在想我平时也不接触啊,工作中无非就是写代码,不会了可以百度,至于类,jvm是怎么加载的我一点也不需要关心.在我刚开始工作的时候也觉得这些底层的内 ...
- rxjs-流式编程
前言 第一次接触rxjs也是因为angular2应用,内置了rxjs的依赖,了解之后发现它的强大,是一个可以代替promise的框架,但是只处理promise的东西有点拿尚方宝剑砍蚊子的意思. 如果我 ...
- CentOS7上LNMP安装包一步搭建LNMP环境
系统需求: CentOS/RHEL/Fedora/Debian/Ubuntu/Raspbian Linux系统 需要5GB以上硬盘剩余空间 需要128MB以上内存(如果为128MB的小内存VPS,Xe ...
- C++学习,两个小的语法错误-network-programming
1.bool CServerSocket::initSocket(const char* ip=NULL,const UINT &port)://会出现默认参数为2的错误 解决方案: //C+ ...
- JS中的Undefined和Null的区别
Undefined ①在声明变量时,如果没有给变量赋值,则这个变量就是undefined类型: ②访问未声明的变量会报错误消息,但这样的变量使用 typeof 测试,返回的值为Undefined. 即 ...
- WC2016自测
挑战NPC 原题链接 爆搜20分,贪心10分,网络流30分 //挑战NPC #include <cstdio> #include <cstring> #include < ...