ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[NOI2015] 品酒大会 题解

2022-09-14 13:01:27  阅读:157  来源: 互联网

标签:old int 题解 mn id NOI2015 品酒 mx rk


[NOI2015] 品酒大会 题解

link

题目大意

给定一个长度为 \(n\) 的字符串 \(s\) ,和第 \(i\) 个位置的权值 \(a_i\)

对于每一个 \(r\in [0,n)\) ,求满足 \(\text{lcp}(i,j)\ge r\) 的 \((i,j)\) 的对数

以及所有的 \((i,j)\) 中, \(a_i\times a_j\) 的最大值

\(n\le 3\times 10^5\)

题解

1

可以转化为倒序枚举 \(r\) 后求 \(\text{lcp}(i,j)=r\) 的 \((i,j)\) 数量以及最大值。

求后缀和、 后缀最大值

2

由于 \(\text{lcp}\) 是 \(rk\) 上连续的一段 \(height\) 的最小值

实际上就是要求区间最小值为 \(r\) 的区间个数

3

将 \(height\) 降序排序,按照顺序加入。

每次在 \(p\) 插入一个数,就是合并两堆数,即 \(p+1\) 和 \(p-1\) 所在堆与 \(p\) 合并。

用并查集维护大小、最值即可。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 5;
int n, sa[N], rk[N], old[N], t[N], id[N], m, h[N];
int fa[N], sz[N];
LL a[N], mx[N], mn[N], s1[N], s2[N], cnt, res = -1e18;
char str[N];
inline void rs() {
	for (int i = 1; i <= m; i++) t[i] = 0;
    for (int i = 1; i <= n; i++) ++t[rk[i]];
    for (int i = 1; i <= m; i++) t[i] += t[i - 1];
    for (int i = n; i >= 1; i--) sa[t[rk[id[i]]]--] = id[i], id[i] = 0;
}
inline int EQ(int x, int y, int k)
{ return old[x] == old[y] && old[x + k] == old[y + k]; }
inline void bui() {
    m = 200;
    for (int i = 1; i <= n; i++) rk[i] = str[i], id[i] = i;
    rs();
    for (int k = 1, p; k <= n; k <<= 1) {
        p = 0;
        for (int i = n - k + 1; i <= n; i++) id[++p] = i;
        for (int i = 1; i <= n; i++) if (sa[i] > k) id[++p] = sa[i] - k;
        rs(), memcpy(old, rk, sizeof(rk)), p = 0;
        for (int i = 1; i <= n; i++) rk[sa[i]] = EQ(sa[i], sa[i - 1], k) ? p : ++p;
        if (p == n) break;
        m = p;
    }
    for (int i = 1, j, k = 0; i <= n; h[rk[i++]] = k)
       	for (k ? --k : 0, j = sa[rk[i] - 1]; str[i + k] == str[j + k]; k++);
}
int fd(int x) {
	while (fa[x] ^ x) x = fa[x] = fa[fa[x]];
	return x;
}
vector<int> b[N];
inline void mer(int x, int y) {
	x = fd(x), y = fd(y);
	cnt += 1ll * sz[x] * sz[y], res = max(res, max(mx[x] * mx[y], mn[x] * mn[y]));
	fa[y] = x, sz[x] += sz[y], mx[x] = max(mx[x], mx[y]), mn[x] = min(mn[x], mn[y]);
}
int main() {
	scanf("%d%s", &n, str + 1);
	for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
	bui();
	for (int i = 1; i <= n; i++) {
		fa[i] = i, sz[i] = 1, mx[i] = mn[i] = a[sa[i]];
		b[h[i]].push_back(i);	
	}
	for (int i = n - 1; ~i; i--) {
//		for (int x : b[i]) mer(x, x - 1);
		int le = b[i].size();
		for (int j = 0; j < le; j++) mer(b[i][j], b[i][j] - 1);
		if (cnt) s1[i] = cnt, s2[i] = res;
	}
	for (int i = 0; i < n; i++) printf("%lld %lld\n", s1[i], s2[i]);
} 

标签:old,int,题解,mn,id,NOI2015,品酒,mx,rk
来源: https://www.cnblogs.com/KonjakLAF/p/16692651.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有