品酒大会

【问题描述】

【输入格式】

【输出格式】

【样例输入】

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. python基础一 day10(2)

    复习: # 三元运算符# 接收结果的变量 = 条件为真的结果 if 条件 else 条件为假的结果# 接收结果的变量 = “真结果” if 条件 else “假结果”## 命名空间 和 作用域# 三种 ...

  2. DS博客作业08--课程总结

    DS博客作业08--课程总结 1.当初你是如何做出选择计算机专业的决定的? 1.1 经过一年学习,你的看法改变了么,为什么? 1.2 你觉得计算机是你喜欢的领域吗,它是你擅长的领域吗? 为什么? 1. ...

  3. objdump命令

    0x00 objdump命令是Linux下的反汇编目标文件或者可执行文件的命令 0x01 objdump -f   显示test的文件头信息 $ objdump -f levellevel: file ...

  4. (1)JSTL的13个core标签库

     标准标签库JSTL的全名为:Java Server Pages Standard Tag Library. (jsp  standard tag library) JSTL主要提供了5大类标签库: ...

  5. vue 点击倒计时 ajax 封装

    方法:function(){ var that = this; if (that.time == 0) { that.disabled = false; that.text ="点击获取&q ...

  6. HTML5开发手机应用--viewport的作用--20150216

    在用HTML5开发手机应用或手机网页时,<head>部分总会有如下一段代码,这段代码到底什么意思呢.在网上,大家会得到很多答案.我从网上搜集了部分介绍,整理一下,以留备用. <met ...

  7. 【Java_多线程并发编程】基础篇—Thread类中start()和run()方法的区别

    1. start() 和 run()的区别说明 start()方法: 它会启动一个新线程,并将其添加到线程池中,待其获得CPU资源时会执行run()方法,start()不能被重复调用. run()方法 ...

  8. perl学习之:理解贪婪匹配和最小匹配之间的区别

    正则表达式的新手经常将贪婪匹配和最小匹配理解错误.默认情况下,Perl 的正则表达式是“贪婪地”,也就是说它们将尽可能多地匹配字符. 下面的脚本打印出“matched defgabcdef”,因为它尽 ...

  9. perl学习之进程管理

    系统函数 == 最简单的系统调用  system "date"; # Perl会将 date 命令传递给unix的shell并获取返回值和error信息等   == 带有系统参数的 ...

  10. PHP中文件锁与进程锁的使用区别

    php中文网的一篇文章,收为己用了.源地址: http://www.php.cn/php-weizijiaocheng-376853.html 本篇文章主要介绍了PHP 文件锁与进程锁的使用示例,小编 ...