题面

Bzoj4199

Sol

后缀数组

显然的暴力就是求\(LCP\)+差分

\(40\)分

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(3e5 + 5); IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
} int a[_], n, s[_], rk[_], sa[_], height[_], tmp[_], t[_];
ll ans1[_], ans2[_];
int st[20][_], lg[_];
char ss[_]; IL int Cmp(RG int i, RG int j, RG int k){
return tmp[i] == tmp[j] && i + k <= n && j + k <= n && tmp[i + k] == tmp[j + k];
} IL void Suffix_Sort(){
RG int m = 26;
for(RG int i = 1; i <= n; ++i) ++t[rk[i] = s[i]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[i]]--] = i;
for(RG int k = 1; k <= n; k <<= 1){
RG int l = 0;
for(RG int i = n - k + 1; i <= n; ++i) tmp[++l] = i;
for(RG int i = 1; i <= n; ++i) if(sa[i] > k) tmp[++l] = sa[i] - k;
for(RG int i = 0; i <= m; ++i) t[i] = 0;
for(RG int i = 1; i <= n; ++i) ++t[rk[tmp[i]]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[tmp[i]]]--] = tmp[i];
swap(tmp, rk), rk[sa[1]] = l = 1;
for(RG int i = 2; i <= n; ++i) rk[sa[i]] = Cmp(sa[i - 1], sa[i], k) ? l : ++l;
if(l >= n) break;
m = l;
}
for(RG int i = 1, h = 0; i <= n; ++i){
if(h) --h;
while(s[i + h] == s[sa[rk[i] - 1] + h]) ++h;
height[rk[i]] = h;
}
} IL void ST_Prepare(){
for(RG int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
for(RG int i = 1; i <= n; ++i) st[0][i] = height[i];
for(RG int i = 1; i <= lg[n]; ++i)
for(RG int j = 1; j + (1 << i) - 1 <= n; ++j)
st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
} IL int LCP(RG int x, RG int y){
x = rk[x], y = rk[y];
if(x > y) swap(x, y); ++x;
RG int len = y - x + 1;
return min(st[lg[len]][x], st[lg[len]][y - (1 << lg[len]) + 1]);
} int main(RG int argc, RG char* argv[]){
Fill(ans2, -127), n = Input(), scanf(" %s", ss + 1);
for(RG int i = 1; i <= n; ++i) s[i] = ss[i] - 'a' + 1, a[i] = Input();
Suffix_Sort(), ST_Prepare();
for(RG int i = 1; i < n; ++i)
for(RG int j = i + 1; j <= n; ++j){
RG int lcp = LCP(i, j);
++ans1[0], --ans1[lcp + 1];
ans2[lcp] = max(ans2[lcp], 1LL * a[i] * a[j]);
}
for(RG int i = 0; i < n; ++i) ans1[i] += ans1[i - 1];
for(RG int i = n - 1; ~i; --i) ans2[i] = max(ans2[i], ans2[i + 1]);
for(RG int i = 0; i < n; ++i) printf("%lld %lld\n", ans1[i], ans2[i] == ans2[n] ? 0 : ans2[i]);
return 0;
}

正解,把\(height\)从大到小排序

每次合并\(height\)两边的集合,因为从大到小,所以两边集合的\(LCP\)一定就是这个\(height\),因为有负数权值,维护集合的最大值,最小值组合

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(3e5 + 5); IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
} int a[_], n, s[_], rk[_], sa[_], height[_], tmp[_], t[_];
ll ans1[_], ans2[_];
int fa[_], id[_], size[_], mx[_], mn[_];
char ss[_]; IL int Cmp(RG int i, RG int j, RG int k){
return tmp[i] == tmp[j] && i + k <= n && j + k <= n && tmp[i + k] == tmp[j + k];
} IL int _Cmp(RG int x, RG int y){
return height[x] > height[y];
} IL void Suffix_Sort(){
RG int m = 26;
for(RG int i = 1; i <= n; ++i) ++t[rk[i] = s[i]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[i]]--] = i;
for(RG int k = 1; k <= n; k <<= 1){
RG int l = 0;
for(RG int i = n - k + 1; i <= n; ++i) tmp[++l] = i;
for(RG int i = 1; i <= n; ++i) if(sa[i] > k) tmp[++l] = sa[i] - k;
for(RG int i = 0; i <= m; ++i) t[i] = 0;
for(RG int i = 1; i <= n; ++i) ++t[rk[tmp[i]]];
for(RG int i = 1; i <= m; ++i) t[i] += t[i - 1];
for(RG int i = n; i; --i) sa[t[rk[tmp[i]]]--] = tmp[i];
swap(tmp, rk), rk[sa[1]] = l = 1;
for(RG int i = 2; i <= n; ++i) rk[sa[i]] = Cmp(sa[i - 1], sa[i], k) ? l : ++l;
if(l >= n) break;
m = l;
}
for(RG int i = 1, h = 0; i <= n; ++i){
if(h) --h;
while(s[i + h] == s[sa[rk[i] - 1] + h]) ++h;
height[rk[i]] = h;
}
} IL int Find(RG int x){
return fa[x] == x ? x : fa[x] = Find(fa[x]);
} int main(RG int argc, RG char* argv[]){
Fill(ans2, -127), n = Input(), scanf(" %s", ss + 1);
for(RG int i = 1; i <= n; ++i) s[i] = ss[i] - 'a' + 1, a[i] = Input();
for(RG int i = 1; i <= n; ++i) fa[i] = id[i] = i, size[i] = 1, mx[i] = mn[i] = a[i];
Suffix_Sort(), sort(id + 2, id + n + 1, _Cmp);
for(RG int i = 2; i <= n; ++i){
RG int fx = Find(sa[id[i] - 1]), fy = Find(sa[id[i]]);
ans1[height[id[i]]] += 1LL * size[fx] * size[fy];
fa[fy] = fx, size[fx] += size[fy];
ans2[height[id[i]]] = max(ans2[height[id[i]]], max(1LL * mx[fx] * mx[fy], 1LL * mx[fx] * mn[fy]));
ans2[height[id[i]]] = max(ans2[height[id[i]]], max(1LL * mn[fx] * mx[fy], 1LL * mn[fx] * mn[fy]));
mx[fx] = max(mx[fx], mx[fy]);
mn[fx] = min(mn[fx], mn[fy]);
}
for(RG int i = n - 1; ~i; --i) ans1[i] += ans1[i + 1], ans2[i] = max(ans2[i], ans2[i + 1]);
for(RG int i = 0; i < n; ++i) printf("%lld %lld\n", ans1[i], ans2[i] == ans2[n] ? 0 : ans2[i]);
return 0;
}

Bzoj4199:[NOI2015]品酒大会的更多相关文章

  1. [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

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

  2. [UOJ#131][BZOJ4199][NOI2015]品酒大会

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

  3. [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp

    品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...

  4. [BZOJ4199][NOI2015]品酒大会

    #131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...

  5. bzoj4199: [Noi2015]品酒大会(后缀数组)

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

  6. BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】

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

  7. 并不对劲的bzoj4199: [Noi2015]品酒大会

    传送门-> 又称普及大会. 这题没什么好说的……后缀自动机裸题……并不对劲的人太菜了,之前照着标程逐行比对才过了这道题,前几天刚刚把这题一遍写对…… 这题的输出和某两点相同后缀的长度有关,那么把 ...

  8. 2019.02.28 bzoj4199: [Noi2015]品酒大会(sam+线段树)

    传送门 题意:给一个串,每个位置有一个权值,当S[s...s+len−1]=S[t...t+len−1]&&S[s...s+len]̸=S[t..t+len]S[s...s+len-1 ...

  9. bzoj千题计划257:bzoj4199: [Noi2015]品酒大会

    http://www.lydsy.com/JudgeOnline/problem.php?id=4199 求出后缀数组的height 从大到小枚举,合并 维护组内 元素个数,最大.次大.最小.次小 # ...

  10. [BZOJ4199][Noi2015]品酒大会 树形DP+后缀自动机

    由于要找后缀的前缀,所以先用反串建立SAM. link边组成了后缀树. 两个子串的最长公共前缀是LCA的step 树形dp即可. #include<iostream> #include&l ...

随机推荐

  1. [Python Study Notes]with的使用

    在 Python 2.5 中, with 关键字被加入.它将常用的 try ... except ... finally ... 模式很方便的被复用.看一个最经典的例子: with open('fil ...

  2. ansible 拷贝文件并重启服务

    Ansible 安装 只需要在ansible 服务器上安装 yum install -y epel-release yum install -y ansible     服务器生成密钥对 ssh-ke ...

  3. Ubuntu配置Nginx虚拟主机和支持ThinkPHP

    [Nginx配置虚拟主机] 每一个 server { listen       80;         server_name  www.a.com; ..... } 就表示一台虚拟域名, 然后对应的 ...

  4. Jquery那些坑

    今天写Jquery的时候突然发现在将$("<td><td/>").appendTo(someElement)的时候发现一下子多出来两个,甚是奇怪,检查后端和 ...

  5. static关键字的使用总结

    1.对于static关键字的使用的时候对于修饰变量的时候,它相当于一个全局变量: 2.对于static修饰一个函数的时候他是在类被加载的时候首先会被类加载,并且只能加载一次,并且这个方法可以不需要通过 ...

  6. ErrorKiller:Failed to decode response: zlib_decode(): data error

    先更新composer自己,composer self-update 然后再更新依赖关系 composer update

  7. Spring data mongodb 替换 Repository 实现类,findAll 排除 字段

    因文档比较大,有时候findAll 不想返回所有数据.没有找到默认的findAll 能够include 或者 exclude 的方法,所以想办法扩展一下实现类 query.fields().inclu ...

  8. Py4j-RPC

    python 使用灵活.方便在科研中被广泛的使用,Numpy和SciPy等科学计算库使其拥有强大的计算方式.很多机器学习和深度学习的库也都采用了python,然而在大数据.后台开发中仍然较多的使用Ja ...

  9. Git 版本退回commit

    有的时候错误提交了commit,需要版本退回. 先用git log查看一下节点版本号commit_id $ git log 再用git reset退回 $ git reset -soft commit ...

  10. swift 学习之自动引用计数

    swift 学习之自动引用计数 学习和研究的主要是"实例对象和实例对象直接的相会强引用所产生的内从泄漏"和"使用闭包产生的强引用造成的内存泄漏" 注意:只有以引 ...