洛谷P2178 品酒大会
题意:若两个字符开始的后面r个字符都一样,则称这两个字符是r相似的。它们也是r-1相似的。
对于r∈[0,n)分别求有多少种方案,其中权值最大方案权值是多少。此处权值是选出的两个字符的权值之积。
解:后缀自动机吊打后缀数组!!!
先看第一问,我们考虑后缀自动机上每个节点的贡献。显然cnt>1的节点才会有贡献。
它会对r ∈ len[fail[x]] + 1 ~ len[x]这一段的答案产生C(cntx,2)的贡献。这就是一个区间加法。
有个小问题,如果r减少那么相应的可选的其实会变多,但是此处我们不统计,那些会在以另一个字符结尾的别的节点上考虑到。
这样第一问就解决了。第二问?发现问题很大...一个节点的每个串都是结尾相同,开头不同。那么开头的权值之积就不好维护。
因为结尾相同,所以考虑反着建后缀自动机,然后就变成了开头相同了。那么如何维护乘积最大值呢?
考虑到一个节点的末尾所在位置,也就是它的right集合。显然就是fail树的子树中所有在主链上的节点。
于是每个点维护子树最大值即可。因为有负数所以还要最小值。
这样一个节点对第二问的贡献就是区间取max了。这两问的操作都可以用线段树搞定。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 typedef long long LL; 6 const int N = 600010; 7 8 int tr[N][26], tot = 1, fail[N], len[N], cnt[N], bin[N], topo[N], last = 1, val[N], n; 9 int max1[N], max2[N], min1[N], min2[N]; 10 char str[N]; 11 LL tag[N << 1], large[N << 1]; 12 13 inline void insert(char c) { 14 int f = c - 'a'; 15 int p = last, np = ++tot; 16 last = np; 17 len[np] = len[p] + 1; 18 cnt[np] = 1; 19 while(p && !tr[p][f]) { 20 tr[p][f] = np; 21 p = fail[p]; 22 } 23 if(!p) { 24 fail[np] = 1; 25 } 26 else { 27 int Q = tr[p][f]; 28 if(len[Q] == len[p] + 1) { 29 fail[np] = Q; 30 } 31 else { 32 int nQ = ++tot; 33 len[nQ] = len[p] + 1; 34 fail[nQ] = fail[Q]; 35 fail[Q] = fail[np] = nQ; 36 memcpy(tr[nQ], tr[Q], sizeof(tr[Q])); 37 while(tr[p][f] == Q) { 38 tr[p][f] = nQ; 39 p = fail[p]; 40 } 41 } 42 } 43 return; 44 } 45 46 inline void update(int x, int y) { 47 int t[4]; 48 t[0] = max1[x]; 49 t[1] = max2[x]; 50 t[2] = max1[y]; 51 t[3] = max2[y]; 52 std::sort(t, t + 4); 53 max1[x] = t[3]; 54 max2[x] = t[2]; 55 t[0] = min1[x]; 56 t[1] = min2[x]; 57 t[2] = min1[y]; 58 t[3] = min2[y]; 59 std::sort(t, t + 4); 60 min1[x] = t[0]; 61 min2[x] = t[1]; 62 return; 63 } 64 65 inline void prework() { 66 for(int i = 1; i <= tot; i++) { 67 bin[len[i]]++; 68 } 69 for(int i = 1; i <= tot; i++) { 70 bin[i] += bin[i - 1]; 71 } 72 for(int i = 1; i <= tot; i++) { 73 topo[bin[len[i]]--] = i; 74 } 75 for(int i = tot; i >= 1; i--) { 76 int a = topo[i]; 77 cnt[fail[a]] += cnt[a]; 78 update(fail[a], a); 79 } 80 return; 81 } 82 83 inline void pushdown(int o) { 84 if(tag[o]) { 85 tag[o << 1] += tag[o]; 86 tag[o << 1 | 1] += tag[o]; 87 tag[o] = 0; 88 } 89 large[o << 1] = std::max(large[o << 1], large[o]); 90 large[o << 1 | 1] = std::max(large[o << 1 | 1], large[o]); 91 return; 92 } 93 94 void add(int L, int R, LL v, int l, int r, int o) { 95 if(L <= l && r <= R) { 96 tag[o] += v; 97 return; 98 } 99 int mid = (l + r) >> 1; 100 pushdown(o); 101 if(L <= mid) { 102 add(L, R, v, l, mid, o << 1); 103 } 104 if(mid < R) { 105 add(L, R, v, mid + 1, r, o << 1 | 1); 106 } 107 return; 108 } 109 110 void out(int l, int r, int o) { 111 if(l == r) { 112 if(r != n) { 113 printf("%lld %lld \n", tag[o], tag[o] ? large[o] : 0); 114 } 115 return; 116 } 117 int mid = (l + r) >> 1; 118 pushdown(o); 119 out(l, mid, o << 1); 120 out(mid + 1, r, o << 1 | 1); 121 return; 122 } 123 124 void change(int L, int R, LL v, int l, int r, int o) { 125 if(v <= large[o]) { 126 return; 127 } 128 if(L <= l && r <= R) { 129 large[o] = v; 130 return; 131 } 132 int mid = (l + r) >> 1; 133 pushdown(o); 134 if(L <= mid) { 135 change(L, R, v, l, mid, o << 1); 136 } 137 if(mid < R) { 138 change(L, R, v, mid + 1, r, o << 1 | 1); 139 } 140 return; 141 } 142 143 int main() { 144 memset(max1, ~0x3f, sizeof(max1)); 145 memset(max2, ~0x3f, sizeof(max2)); 146 memset(min1, 0x3f, sizeof(min1)); 147 memset(min2, 0x3f, sizeof(min2)); 148 memset(large, ~0x3f, sizeof(large)); 149 scanf("%d", &n); 150 scanf("%s", str + 1); 151 int l1 = -0x3f3f3f3f, l2 = -0x3f3f3f3f, s1 = 0x3f3f3f3f, s2 = 0x3f3f3f3f; 152 for(int i = 1; i <= n; i++) { 153 scanf("%d", &val[i]); 154 if(l1 < val[i]) { 155 l2 = l1; 156 l1 = val[i]; 157 } 158 else if(l2 < val[i]) { 159 l2 = val[i]; 160 } 161 if(s1 > val[i]) { 162 s2 = s1; 163 s1 = val[i]; 164 } 165 else if(s2 > val[i]) { 166 s2 = val[i]; 167 } 168 } 169 for(int i = n; i >= 1; i--) { 170 insert(str[i]); 171 max1[last] = min1[last] = val[i]; 172 } 173 prework(); 174 // 175 for(int i = 2; i <= tot; i++) { 176 if(cnt[i] < 2) { 177 continue; 178 } 179 // len[fail[i]] + 1 ~ len[i] 180 add(len[fail[i]] + 1, len[i], 1ll * cnt[i] * (cnt[i] - 1) / 2, 1, n, 1); 181 change(len[fail[i]] + 1, len[i], std::max(1ll * max1[i] * max2[i], 1ll * min1[i] * min2[i]), 1, n, 1); 182 } 183 184 printf("%lld %lld \n", 1ll * n * (n - 1) / 2, std::max(1ll * l1 * l2, 1ll * s1 * s2)); 185 out(1, n, 1); 186 return 0; 187 }
AC代码
转载于:https://www.cnblogs.com/huyufeifei/p/10328366.html
洛谷P2178 品酒大会相关推荐
- 洛谷P2178 [NOI2015]品酒大会 后缀数组+单调栈
P2178 [NOI2015]品酒大会 题目链接 https://www.luogu.org/problemnew/show/P2178 题目描述 一年一度的"幻影阁夏日品酒大会" ...
- 洛谷 P2178 [NOI2015]品酒大会 解题报告
P2178 [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和 ...
- UOJ #131 BZOJ 4199 luogu P2178【NOI2015】品酒大会 (后缀自动机、树形DP)
UOJ #131 BZOJ 4199 luogu P2178[NOI2015]品酒大会 (后缀自动机.树形DP) 水是水,但是写出了不少问题,因此写一发博客. https://www.luogu.or ...
- [BZOJ4199][NOI2015]品酒大会-后缀数组
品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手" ...
- 洛谷 - 试炼场(全部题目备份)
整理的算法模板合集: ACM模板 目录 1.新手村 1 - 1 洛谷的第一个任务 1 - 2 顺序与分支 1 - 3 循环!循环!循环! 1 - 4 数组 1 - 5 简单字符串 1 - 6 过程函数 ...
- 洛谷 1373 dp 小a和uim之大逃离 良心题解
洛谷 1373 dp 这题还不算太难,,当初看的时候不是很理解题意,以为他们会选择两条不同的路径,导致整体思路混乱 传送门 其实理解题意和思路之后还是敲了不短的时间,一部分身体原因再加上中午休息不太好 ...
- 【洛谷】 P1240 诸侯安置(递推)
洛谷P1240 诸侯安置 点击此处去OJ 问题描述 很久以前,有一个强大的帝国,它的国土成正方形状(需旋转45°来看),图1所示为n=3时的情况.这个国家有若干诸侯.由于这些诸侯都曾立下赫赫战功,因此 ...
- 洛谷千题复习计划(一)(Codeforces + AtCoder)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 每天花一个小时简单复习一下我写过的洛谷的题目! 虽然还没有到千题,但是快了(等我复习完这些以后我 lu ...
- 洛谷-题解 P2672 【推销员】
独门思路!链表加优先队列! 这题一望,贪心是跑不掉了,但是我贪心并不好,所以想到了一个复杂一些但思路更保稳的做法 思路: 1 因为是离线操作,所以我们可以倒着求,先求x=n的情况,因为那样直接就知道了 ...
最新文章
- GT Transceiver的电源控制
- iOS 9音频应用开发基础教程(大学霸内部资料)
- 全球三大芯片架构之一MIPS倒下!转身投入RISC-V阵营
- [转]ToolTip在VC中的使用
- 【励志】高考失利之后,属于我的大学本科四年
- oracle查询orapw文件,oracle学习笔记《一》
- vue上传文件php,php文件上传 – 前端开发,JQUERY特效,全栈开发,vue开发
- 2017年最新基于Bootstrap 4 的专业、多用途响应式布局的系统模板
- 【Jmeter篇】Linux环境下安装部署运行Jmeter
- VS2019添加自定义发布本地的Nuget(.nupkg文件)
- C# .NET 如何修改代码字体
- 软考备考-系统构架师-21-系统架构师考纲整理
- 浙江概况——经济发展篇
- 深入java虚拟机视频教程_从原理到实战深入学习JAVA虚拟机,视频教程下载
- 【短视频运营】查找对标账号 ( 关键词搜索 | 第三方工具查找 | 对标账号学习 | 视频文案 | #话题 | 评论内容 | 历史视频 )
- 多米诺DP(双向背包)算法总结
- 让你的微信小程序对用户更加友好:上拉加载和下拉刷新就是关键
- 利用MATLAB将图片转换成coe文件、TXT文件、mif文件、bin文件
- 轩小陌的Python笔记-day25 MySQL入门
- 磁盘空间linux命令fdisk,解决fdisk与df命令显示的磁盘空间不一样