题意:若两个字符开始的后面r个字符都一样,则称这两个字符是r相似的。它们也是r-1相似的。

对于r∈[0,n)分别求有多少种方案,其中权值最大方案权值是多少。此处权值是选出的两个字符的权值之积。

解:后缀自动机吊打后缀数组!!!

先看第一问,我们考虑后缀自动机上每个节点的贡献。显然cnt>1的节点才会有贡献。

它会对r ∈ len[fail[x]] + 1  ~  len[x]这一段的答案产生C(cntx,2)的贡献。这就是一个区间加法。

有个小问题,如果r减少那么相应的可选的其实会变多,但是此处我们不统计,那些会在以另一个字符结尾的别的节点上考虑到。

这样第一问就解决了。第二问?发现问题很大...一个节点的每个串都是结尾相同,开头不同。那么开头的权值之积就不好维护。

因为结尾相同,所以考虑反着建后缀自动机,然后就变成了开头相同了。那么如何维护乘积最大值呢?

考虑到一个节点的末尾所在位置,也就是它的right集合。显然就是fail树的子树中所有在主链上的节点。

于是每个点维护子树最大值即可。因为有负数所以还要最小值。

这样一个节点对第二问的贡献就是区间取max了。这两问的操作都可以用线段树搞定。

 #include <cstdio>
#include <cstring>
#include <algorithm> typedef long long LL;
const int N = ; int tr[N][], tot = , fail[N], len[N], cnt[N], bin[N], topo[N], last = , val[N], n;
int max1[N], max2[N], min1[N], min2[N];
char str[N];
LL tag[N << ], large[N << ]; inline void insert(char c) {
int f = c - 'a';
int p = last, np = ++tot;
last = np;
len[np] = len[p] + ;
cnt[np] = ;
while(p && !tr[p][f]) {
tr[p][f] = np;
p = fail[p];
}
if(!p) {
fail[np] = ;
}
else {
int Q = tr[p][f];
if(len[Q] == len[p] + ) {
fail[np] = Q;
}
else {
int nQ = ++tot;
len[nQ] = len[p] + ;
fail[nQ] = fail[Q];
fail[Q] = fail[np] = nQ;
memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
while(tr[p][f] == Q) {
tr[p][f] = nQ;
p = fail[p];
}
}
}
return;
} inline void update(int x, int y) {
int t[];
t[] = max1[x];
t[] = max2[x];
t[] = max1[y];
t[] = max2[y];
std::sort(t, t + );
max1[x] = t[];
max2[x] = t[];
t[] = min1[x];
t[] = min2[x];
t[] = min1[y];
t[] = min2[y];
std::sort(t, t + );
min1[x] = t[];
min2[x] = t[];
return;
} inline void prework() {
for(int i = ; i <= tot; i++) {
bin[len[i]]++;
}
for(int i = ; i <= tot; i++) {
bin[i] += bin[i - ];
}
for(int i = ; i <= tot; i++) {
topo[bin[len[i]]--] = i;
}
for(int i = tot; i >= ; i--) {
int a = topo[i];
cnt[fail[a]] += cnt[a];
update(fail[a], a);
}
return;
} inline void pushdown(int o) {
if(tag[o]) {
tag[o << ] += tag[o];
tag[o << | ] += tag[o];
tag[o] = ;
}
large[o << ] = std::max(large[o << ], large[o]);
large[o << | ] = std::max(large[o << | ], large[o]);
return;
} void add(int L, int R, LL v, int l, int r, int o) {
if(L <= l && r <= R) {
tag[o] += v;
return;
}
int mid = (l + r) >> ;
pushdown(o);
if(L <= mid) {
add(L, R, v, l, mid, o << );
}
if(mid < R) {
add(L, R, v, mid + , r, o << | );
}
return;
} void out(int l, int r, int o) {
if(l == r) {
if(r != n) {
printf("%lld %lld \n", tag[o], tag[o] ? large[o] : );
}
return;
}
int mid = (l + r) >> ;
pushdown(o);
out(l, mid, o << );
out(mid + , r, o << | );
return;
} void change(int L, int R, LL v, int l, int r, int o) {
if(v <= large[o]) {
return;
}
if(L <= l && r <= R) {
large[o] = v;
return;
}
int mid = (l + r) >> ;
pushdown(o);
if(L <= mid) {
change(L, R, v, l, mid, o << );
}
if(mid < R) {
change(L, R, v, mid + , r, o << | );
}
return;
} int main() {
memset(max1, ~0x3f, sizeof(max1));
memset(max2, ~0x3f, sizeof(max2));
memset(min1, 0x3f, sizeof(min1));
memset(min2, 0x3f, sizeof(min2));
memset(large, ~0x3f, sizeof(large));
scanf("%d", &n);
scanf("%s", str + );
int l1 = -0x3f3f3f3f, l2 = -0x3f3f3f3f, s1 = 0x3f3f3f3f, s2 = 0x3f3f3f3f;
for(int i = ; i <= n; i++) {
scanf("%d", &val[i]);
if(l1 < val[i]) {
l2 = l1;
l1 = val[i];
}
else if(l2 < val[i]) {
l2 = val[i];
}
if(s1 > val[i]) {
s2 = s1;
s1 = val[i];
}
else if(s2 > val[i]) {
s2 = val[i];
}
}
for(int i = n; i >= ; i--) {
insert(str[i]);
max1[last] = min1[last] = val[i];
}
prework();
//
for(int i = ; i <= tot; i++) {
if(cnt[i] < ) {
continue;
}
// len[fail[i]] + 1 ~ len[i]
add(len[fail[i]] + , len[i], 1ll * cnt[i] * (cnt[i] - ) / , , n, );
change(len[fail[i]] + , len[i], std::max(1ll * max1[i] * max2[i], 1ll * min1[i] * min2[i]), , n, );
} printf("%lld %lld \n", 1ll * n * (n - ) / , std::max(1ll * l1 * l2, 1ll * s1 * s2));
out(, n, );
return ;
}

AC代码

洛谷P2178 品酒大会的更多相关文章

  1. 洛谷P2178 品酒大会【后缀数组】【单调栈】

    题目描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainb ...

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

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

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

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

  4. 洛谷P2178 [NOI2015]品酒大会

    题目描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainb ...

  5. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

  6. 【BZOJ4199】【NOI2015】品酒大会(后缀数组)

    [BZOJ4199][NOI2015]品酒大会 题面 BZOJ Uoj 洛谷 题解 考虑最裸的暴力 枚举每次的长度 以及两个开始的位置 检查以下是否满足条件,如果可以直接更新答案 复杂度\(O(n^3 ...

  7. [BZOJ]4199 品酒大会(Noi2015)

    讲道理是后缀数组裸题吧,虽然知道后缀数组的原理但是小C不会写是什么鬼.. 小C趁着做这题的当儿,学习了一下后缀数组. 网络上的后缀数组模板完全看不懂怎么破,全程照着黄学长的代码抄,感觉黄学长写得还是很 ...

  8. NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp

    原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...

  9. BZOJ4199:[NOI2015]品酒大会——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4199 https://www.luogu.org/problemnew/show/P2178#su ...

随机推荐

  1. CentOS7安装Jenkins自动化部署maven项目

    前言: 最近要弄一个jenkins工具,已经安装好了并且jenkins使用部署项目的流程已经基本走通,上图: 话不多说,开始 第一步:安装jenkins: [ 准备环境: 在centOS7环境上:安装 ...

  2. WPF中元素拖拽的两个实例

    今天结合之前做过的一些拖拽的例子来对这个方面进行一些总结,这里主要用两个例子来说明在WPF中如何使用拖拽进行操作,元素拖拽是一个常见的操作,第一个拖拽的例子是将ListBox中的子元素拖拽到ListV ...

  3. 在delphi中生成GUID

    什么是 GUID ? 全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装.在许多流行软件应用程序(例如 Web 浏览器和媒体播放器)中,都使用 GUID. GUID 的格式为 ...

  4. 洛谷 P1141 01迷宫

    看似普通的 bfs 题(实际上也不怎么难 主要是我太菜了) 题目链接:https://www.luogu.org/problemnew/show/P1141 如果直接用简单的bfs一顿求的话,会超时( ...

  5. 去掉AMD锐龙和Intel Kaby Lake的不支持的硬件的提示

    Windows 7和Windows 8.1都不支持AMD Ryzen 锐龙系列和Intel最新的Kaby Lake系列,Windows Update 更新之后总是会提示“不支持的硬件(Unsuppor ...

  6. jsp页面给字体加颜色

    jsp页面给字体加颜色<span style="color:red">要加颜色的部分</span>

  7. EUV光刻!宇宙最强DDR4内存造出

    三星电子宣布开发出业内首款基于第三代10nm级工艺的DRAM内存芯片,将服务于高端应用场景,这距离三星量产1y nm 8Gb DDR4内存芯片仅过去16个月. 第三代10nm级工艺即1z nm(在内存 ...

  8. C# Timer 的区别

    首先,我们看一下 3种Timer 1.System.Threading.Timer 2.System.Timers.Timer 3.System.Windows.Forms.Timer 主要区别,其实 ...

  9. Android 9.png图片的制作方法

    在Android的设计过程中,为了适配不同的手机分辨率,图片大多需要拉伸或者压缩,这样就出现了可以任意调整大小的一种图片格式".9.png".这种图片是用于Android开发的一种 ...

  10. [模板] Manacher(马拉车)算法

    用途 求回文子串 做法 先考虑回文子串以某字符为中心的情况,即长度为奇数 推着做,记rad[i]为以i位置为中心的最大半径(包含中点) 考虑怎么求rad[i].找之前的一个右端点最靠右的位置p,设它的 ...