品酒大会

【问题描述】

【输入格式】

【输出格式】

【样例输入】

10
ponoiiipoi
2 1 4 7 4 8 3 6 4 7

【样例输出】

45 56
10 56
3 32
0 0
0 0
0 0
0 0
0 0
0 0
0 0

【数据范围】


题解:

根据题意可得"r相似”也是“r - 1相似”

那么我们只要求出了所有最大为 r 相似的对数,就可以利用后缀和求出所有r相似的个数

考虑一瓶酒与另一瓶酒如果是 r 相似的,那么与其中一瓶酒 k (k > r) 相似的酒与另一瓶酒最大也为 r 相似

所以用后缀数组求出 height 数组

然后按 height 从大到小排序

每次按顺序找出两个 height 相似的点的祖先

height 相似的对数累加上两个祖先块内的点数乘积

height 相似的最大值为两个块的最小值乘积和最大值乘积的较大值

用并查集合并,处理点的个数、最大值和最小值(美味度有负数)

最后跑一遍后缀和

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
inline void Scan(int &x)
{
char c;
int o = ;
while((c = getchar()) < '' || c > '')
if(c == '-') o = -;
x = c - '';
while((c = getchar()) >= '' && c <= '') x = x * + c - '';
x *= o;
}
const int me = ;
int n;
int w[me];
int x[me];
int sa[me], he[me];
int val[me], fat[me], nex[me];
int rank[me];
long long ans_si[me], ans_mx[me];
char s[me];
struct Union
{
long long si, mx, mi;
};
Union un[me];
inline void Sa()
{
int m = ;
for(int i = ; i <= n; ++i) ++w[x[i] = s[i] - 'a' + ];
for(int i = ; i <= m; ++i) w[i] += w[i - ];
for(int i = n; i >= ; --i) sa[w[x[i]]--] = i;
for(int k = ; k <= n; k <<= )
{
int p = ;
for(int i = n; i >= n - k + ; --i) rank[++p] = i;
for(int i = ; i <= n; ++i)
if(sa[i] > k)
rank[++p] = sa[i] - k;
for(int i = ; i <= m; ++i) w[i] = ;
for(int i = ; i <= n; ++i) ++w[x[i]];
for(int i = ; i <= m; ++i) w[i] += w[i - ];
for(int i = n; i >= ; --i) sa[w[x[rank[i]]]--] = rank[i];
m = ;
for(int i = ; i <= n; ++i)
{
int u = sa[i], v = sa[i - ];
if(x[u] != x[v] || x[u + k] != x[v + k]) rank[u] = ++m;
else rank[u] = m;
}
if(n == m) break;
for(int i = ; i <= n; ++i) swap(x[i], rank[i]);
}
int tot = ;
int i, j;
for(i = ; i <= n; i ++)
{
if (tot) tot --;
j = sa[rank[i] - ];
while (s[j + tot] == s[i + tot]) tot ++;
he[rank[i]] = tot;
}
}
inline bool rule(const int &x, const int &y)
{
return he[x] > he[y];
}
inline int Find(const int &x)
{
return (x != fat[x]) ? fat[x] = Find(fat[x]) : x;
}
inline void Un(const int &x, const int &y)
{
un[x].si += un[y].si;
un[x].mx = max(un[x].mx, un[y].mx);
un[x].mi = min(un[x].mi, un[y].mi);
fat[y] = x;
}
int main()
{
Scan(n);
scanf("%s", s + );
for(int i = ; i <= n; ++i)
{
Scan(val[i]);
nex[i] = i + ;
fat[i] = i;
}
Sa();
for(int i = ; i <= n; ++i)
ans_mx[i] = -;
for(int i = ; i <= n; ++i)
un[i] = (Union) {, val[sa[i]], val[sa[i]]};
sort(nex + , nex + n, rule);
for(int i = ; i < n; ++i)
{
int x = Find(nex[i] - ), y = Find(nex[i]);
int z = he[nex[i]];
ans_si[z] += un[x].si * un[y].si;
ans_mx[z] = max(ans_mx[z], max(un[x].mi * un[y].mi, un[x].mx * un[y].mx));
Un(x, y);
}
for(int i = n - ; i >= ; --i)
{
ans_si[i] += ans_si[i + ];
ans_mx[i] = max(ans_mx[i], ans_mx[i + ]);
}
for(int i = ; i < n; ++i)
printf("%lld %lld\n", ans_si[i], ans_si[i] ? ans_mx[i] : );
}

品酒大会 BZOJ 4199的更多相关文章

  1. [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

    [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...

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

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

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

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

  4. bzoj 4199 && NOI 2015 品酒大会

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

  5. bzoj 4199: [Noi2015]品酒大会

    Description 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手&quo ...

  6. 【刷题】BZOJ 4199 [Noi2015]品酒大会

    Description 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手&quo ...

  7. 4199. [NOI2015]品酒大会【后缀数组+并查集】

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

  8. 【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合

    4199: [Noi2015]品酒大会 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 436  Solved: 243[Submit][Status] ...

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

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

随机推荐

  1. 漫谈 Clustering (4): Spectral Clustering<转载>

    转自http://blog.pluskid.org/?p=287 如果说 K-means 和 GMM 这些聚类的方法是古代流行的算法的话,那么这次要讲的 Spectral Clustering 就可以 ...

  2. Python 解压序列、可迭代对象并赋值给多个变量

    Python数据结构和类型 1.1 解压序列赋值给多个变量 现在有一个包含N个元素的元组或者是序列,怎样将它里面的值解压后同时赋值给N个变量? 解决思路:先通过简单的解压赋值给多个变量,前提是变量的数 ...

  3. 浅谈倍增LCA

    题目链接:https://www.luogu.org/problemnew/show/P3379 刚学了LCA,写篇blog加强理解. LCA(Least Common Ancestors),即最近公 ...

  4. ios 自定义RadioButton

    1 前言 众所周知在IOS中没有单选按钮这一控件,今天我们来学习一下简单的单选控件.类似与Web中的radio表单元素. 2 详述 本控件单纯的利用按钮控件和NSObject的respondsToSe ...

  5. makeObjectsPerformSelector用法

    亲测 makeObjectsPerformSelector 的用法. - (void)makeObjectsPerformSelector:(SEL)aSelector NS_SWIFT_UNAVAI ...

  6. 洛谷 P2846 光开关

    https://www.luogu.org/problemnew/show/P2846 好多题解用线段树来写,然而分块不是更简单好些吗? 一个数组use记录这一块进行了多少次开关操作,两边单独计算,注 ...

  7. idea 插件推荐 & 代码样式安装

    部分链接打不开的可能需要梯子, 部分插件我懒得截图了,麻烦 ---------------------------------------header------------------------- ...

  8. 数据结构( Pyhon 语言描述 ) — —第11章:集和字典

    使用集 集是没有特定顺序的项的一个集合,集中的项中唯一的 集上可以执行的操作 返回集中项的数目 测试集是否为空 向集中添加一项 从集中删除一项 测试给定的项是否在集中 获取两个集的并集 获取两个集的交 ...

  9. 使用VMware克隆出来的新虚拟机无法联网-问题解决记录

    背景: 使用VMware克隆出来的新虚拟机无法联网,重启网卡出现如下图提示: 继续输入#ifup ens33 提示: ens33: unknown interface: No such device ...

  10. Python9-模块1-day19

    在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter.deque.defaultdict.namedtuple和Ord ...