题解

想出了一个神奇的技巧

我们先把串反过来(因为我们需要起始位置的值而不是终止位置的值),每个点维护一下 fail树上子树里的点,作为正数绝对值最大的两个数,作为负数绝对值最大的两个数

我们发现这个两两相乘的最大值肯定是一个后缀最大值,我们对每个节点求一个最大值存到这个节点的len处理出后缀最大值就行

然后关键是怎么求这个多少个位置两两匹配前缀是0,1,2....n - 1

似乎会想到把后缀自动机上节点的cnt累加进去就好?然而,这样是错的,你连第一个样例都过不了

为什么呢,我们把样例第一个串反过来之后看一看

ponoiiipoi

iopiiionop

你如果要统计两个p的位置作为相同长度为1的两个位置

非常尴尬,没有这个节点

怎么办,你BFS显然会超时……为什么i这个位置就会被统计进去……因为有这个节点

ii这个节点的par就是i

经过一番大胆的猜想,发现我们需要把\([p->par->len + 1,p->len]\)这一段的答案要加上\(p->cnt *(p->cnt - 1) / 2\)

那么为什么这样是正确的呢……显然= =

因为p->par就是p的一段后缀,这段后缀显然会累加上由于最长匹配是个长串带来的贡献,而中间的一段也是这个长串的一部分,没有被加上

代码

  1. #include <bits/stdc++.h>
  2. //#define ivorysi
  3. #define enter putchar('\n')
  4. #define space putchar(' ')
  5. #define fi first
  6. #define se second
  7. #define pb push_back
  8. #define mp make_pair
  9. #define eps 1e-8
  10. #define mo 974711
  11. #define MAXN 300005
  12. #define pii pair<int,int>
  13. using namespace std;
  14. typedef long long int64;
  15. typedef double db;
  16. template<class T>
  17. void read(T &res) {
  18. res = 0;char c = getchar();T f = 1;
  19. while(c < '0' || c > '9') {
  20. if(c == '-') f = -1;
  21. c = getchar();
  22. }
  23. while(c >= '0' && c <= '9') {
  24. res = res * 10 + c - '0';
  25. c = getchar();
  26. }
  27. res *= f;
  28. }
  29. template<class T>
  30. void out(T x) {
  31. if(x < 0) {putchar('-');x = -x;}
  32. if(x >= 10) {
  33. out(x / 10);
  34. }
  35. putchar('0' + x % 10);
  36. }
  37. struct node {
  38. int len,cnt;
  39. int val[2][2],vc[2];
  40. node *nxt[26],*par;
  41. }pool[MAXN * 2],*tail = pool,*root,*last,*que[MAXN * 2];
  42. int a[MAXN],N,c[MAXN];
  43. int64 ans[MAXN],sum[MAXN],d[MAXN];
  44. char str[MAXN];
  45. void build_SAM(int e,int len,int v) {
  46. node *nowp = tail++,*p;
  47. nowp->len = len;nowp->cnt = 1;
  48. if(v < 0) nowp->val[0][nowp->vc[0]++] = v;
  49. else nowp->val[1][nowp->vc[1]++] = v;
  50. for(p = last ; p && !p->nxt[e] ; p = p->par) {
  51. p->nxt[e] = nowp;
  52. }
  53. if(!p) nowp->par = root;
  54. else {
  55. node *q = p->nxt[e];
  56. if(q->len == p->len + 1) nowp->par = q;
  57. else {
  58. node *copyq = tail++;
  59. *copyq = *q;
  60. copyq->vc[0] = copyq->vc[1] = 0;
  61. memset(copyq->val,0,sizeof(copyq->val));
  62. copyq->cnt = 0;
  63. copyq->len = p->len + 1;
  64. q->par = nowp->par = copyq;
  65. for(; p && p->nxt[e] == q ; p = p->par) p->nxt[e] = copyq;
  66. }
  67. }
  68. last = nowp;
  69. }
  70. void update(node *p,int on,int v) {
  71. if(p->vc[on] < 2) {p->val[on][1] = v;++p->vc[on];}
  72. else {
  73. if(abs(v) > abs(p->val[on][1])) p->val[on][1] = v;
  74. }
  75. if(abs(p->val[on][1]) > abs(p->val[on][0])) swap(p->val[on][1],p->val[on][0]);
  76. }
  77. void Init() {
  78. read(N);scanf("%s",str + 1);
  79. for(int i = 1 ; i <= N ; ++i) read(a[i]);
  80. for(int i = 1 ; i <= N / 2 ; ++i) {
  81. swap(a[i],a[N - i + 1]);swap(str[i],str[N - i + 1]);
  82. }
  83. root = last = tail++;
  84. for(int i = 1 ; i <= N ; ++i) build_SAM(str[i] - 'a',i,a[i]);
  85. }
  86. void Solve() {
  87. int m = tail - pool;
  88. for(int i = 0 ; i < m ; ++i) c[pool[i].len]++;
  89. for(int i = 1 ; i <= N ; ++i) c[i] += c[i - 1];
  90. for(int i = 0 ; i < m ; ++i) que[c[pool[i].len]--] = &pool[i];
  91. for(int i = 0 ; i <= N ; ++i) ans[i] = -1e18;
  92. for(int i = m ; i >= 1 ; --i) {
  93. if(que[i]->cnt > 1) {
  94. sum[que[i]->len] += 1LL * (que[i]->cnt - 1) * (que[i]->cnt) / 2;
  95. if(que[i]->vc[0] >= 2) ans[que[i]->len] = max(ans[que[i]->len],1LL * que[i]->val[0][1] * que[i]->val[0][0]);
  96. if(que[i]->vc[1] >= 2) ans[que[i]->len] = max(ans[que[i]->len],1LL * que[i]->val[1][0] * que[i]->val[1][1]);
  97. for(int k = 0 ;k < que[i]->vc[0] ; ++k) {
  98. for(int h = 0 ; h < que[i]->vc[1] ; ++h) {
  99. ans[que[i]->len] = max(ans[que[i]->len],1LL * que[i]->val[0][k] * que[i]->val[1][h]);
  100. }
  101. }
  102. }
  103. d[que[i]->len - 1] += 1LL * (que[i]->cnt - 1) * que[i]->cnt / 2;
  104. if(que[i]->par) {
  105. que[i]->par->cnt += que[i]->cnt;
  106. for(int k = 0 ; k < que[i]->vc[0] ; ++k) {
  107. update(que[i]->par,0,que[i]->val[0][k]);
  108. }
  109. for(int k = 0 ; k < que[i]->vc[1] ; ++k) {
  110. update(que[i]->par,1,que[i]->val[1][k]);
  111. }
  112. d[que[i]->par->len] -= 1LL * (que[i]->cnt - 1) * que[i]->cnt / 2;
  113. }
  114. }
  115. for(int i = N ; i >= 1 ; --i) d[i] += d[i + 1],sum[i] += d[i];
  116. for(int i = N - 1; i >= 1 ; --i) ans[i] = max(ans[i + 1],ans[i]);
  117. for(int i = 0 ; i <= N - 1 ; ++i) {
  118. if(!sum[i]) ans[i] = 0;
  119. out(sum[i]);space;out(ans[i]);enter;
  120. }
  121. }
  122. int main() {
  123. #ifdef ivorysi
  124. freopen("f1.in","r",stdin);
  125. #endif
  126. Init();
  127. Solve();
  128. return 0;
  129. }

【LOJ】#2133. 「NOI2015」品酒大会的更多相关文章

  1. loj#2129. 「NOI2015」程序自动分析

    题目链接 loj#2129. 「NOI2015」程序自动分析 题解 额... 考你会不会离散化优化常数 代码 #include<queue> #include<cstdio> ...

  2. *LOJ#2134. 「NOI2015」小园丁与老司机

    $n \leq 5e4$个平面上的点,从原点出发,能从当前点向左.右.上.左上或右上到达该方向最近的给定点.问三个问:一.最多经过多少点:二.前一问的方案:三.其所有方案种非左右走的边至少要开几辆挖掘 ...

  3. LOJ#2132. 「NOI2015」荷马史诗

    $n \leq 100000$个数字,放进$k$叉树里,一个点只能放一个数,使所有数字乘以各自深度这个值之和最小的同时,最大深度的数字最小. 哈夫曼.这是我刚学OI那段时间看到的,感觉就是个很无聊的贪 ...

  4. LOJ#2131. 「NOI2015」寿司晚宴

    $n \leq 500$,$2-n$这些数字,两个人挑,可以重复挑,问有几种方案中,一个人选的所有数字与另一个人选的所有数字都互质. 不像前两题那么抠脚.. 如果$n$比较小的话,可以把两个人选的数字 ...

  5. Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集

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

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

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

  7. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  8. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  9. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

随机推荐

  1. UESTC--1727

    原题链接:http://acm.uestc.edu.cn/problem.php?pid=1727 分析:用 l[i] 记录第 i 层楼有多少物品需要往上继续搬运,如果某层楼没有物品,但是更上面还有, ...

  2. Linux常用网络工具:fping主机扫描

    Linux下有很多强大网络扫描工具,网络扫描工具可以分为:主机扫描.主机服务扫描.路由扫描等. fping是一个主机扫描工具,相比于ping工具可以批量扫描主机. fping官方网站:http://f ...

  3. 题解 UVA1184 【Air Raid】

    有向无环图(DAG)的最小路径覆盖的模板题. 定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点. 由题意可得这是一个有向图,而路径不能相交,于是我们知道这是无向图的不相交最小路径覆盖问 ...

  4. 下载外部jar包后,链接源码和javadoc.jar

    今天下载了一个Apache Common的一个jar包,对于引入源码和JavaDoc有了新的认识,在这里记录一下. Binaries是指二进制文件,包含使用的jar包.Source是指源码. xxx. ...

  5. 前端PHP入门-023-重点日期函数之程序执行时间检测

    我们有的时经常需要做程序的执行时间执行效率判断. 实现的思路如下: <?php //记录开始时间 //记录结整时 // 开始时间 减去(-) 结束时间 得到程序的运行时间 ?> 可是大家不 ...

  6. 【转】手摸手,带你用vue撸后台 系列二(登录权限篇)

    前言 拖更有点严重,过了半个月才写了第二篇教程.无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅. 进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常 ...

  7. [SDOI2005]区间

    题目描述 现给定n个闭区间[ai, bi],1<=i<=n.这些区间的并可以表示为一些不相交的闭区间的并.你的任务就是在这些表示方式中找出包含最少区间的方案.你的输出应该按照区间的升序排列 ...

  8. POJ 1228 Grandpa's Estate 凸包 唯一性

    LINK 题意:给出一个点集,问能否够构成一个稳定凸包,即加入新点后仍然不变. 思路:对凸包的唯一性判断,对任意边判断是否存在三点及三点以上共线,如果有边不满足条件则NO,注意使用水平序,这样一来共线 ...

  9. LightOJ 1244 - Tiles 猜递推+矩阵快速幂

    http://www.lightoj.com/volume_showproblem.php?problem=1244 题意:给出六种积木,不能旋转,翻转,问填充2XN的格子有几种方法.\(N < ...

  10. fastreport中文乱码问题

    fastreport的中文乱码问题,确实让人头疼,我使用的是delphi6+fastrepport4.7,在4.7版本中,主要表现在以下几种情况. 预览不乱码,保存乱码. 简体不乱码,繁体乱码. 简体 ...