题目

哈哈哈哈哈哈哈哈哈哈我还没自闭

好像前后调了两天了

哈哈哈哈哈哈哈哈哈哈我还没自闭

这道题就是给定一个小写字母串,回答分别把每个位置上的字符替换为\(#\)后的本质不同的子串数

首先就是跨过这个特殊字符的字符串出现次数显然都是\(1\),这部分的贡献就直接是\(i\times(n-i+1)\)

之后我们用\(SAM\)搞出所有前缀和所有后缀的本质不同子串个数,这时候答案的贡献就是\(pre_{i-1}+beh_{i+1}\)

显然会算多一些在前缀和后缀里都出现的子串

想个办法把这些东西搞出来

我们维护出每个等价类\(endpos\)的最大值\(mx[i]\)和最小值\(mi[i]\)

显然如果特殊字符插入在\([mi[i],mx[i]-len[i]]\)里的话会使得这个字符串在左右两边都被算过

如果特殊字符插入在\([mx[i]-len[i]+1,mx-len[fa[i]]\),发现这里好像需要一个每往后移动一个位置就会少多算一个子串,那就是一个公差为\(-1\)的等差数列啊,二阶差分维护一下就好了

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #define max(a,b) ((a)>(b)?(a):(b))
  6. #define min(a,b) ((a)<(b)?(a):(b))
  7. #define LL long long
  8. #define re register
  9. #define maxn 600005
  10. char S[maxn>>1];
  11. struct SAM{
  12. int len[maxn],fa[maxn],son[maxn][26];
  13. LL tot;int lst,cnt;
  14. inline void ins(int c) {
  15. int p=++cnt,f=lst;lst=p;
  16. len[p]=len[f]+1;
  17. while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
  18. if(!f) {fa[p]=1;tot+=len[p]-len[fa[p]];return;}int x=son[f][c];
  19. if(len[f]+1==len[x]) {fa[p]=x;tot+=len[p]-len[fa[p]];return;}
  20. int y=++cnt;tot-=len[x]-len[fa[x]];
  21. len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
  22. tot+=len[y]-len[fa[y]],tot+=len[p]-len[fa[p]],tot+=len[x]-len[fa[x]];
  23. for(re int i=0;i<26;i++) son[y][i]=son[x][i];
  24. while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
  25. }
  26. }S1,S2;
  27. int n;
  28. LL pre[maxn],beh[maxn];
  29. int len[maxn],fa[maxn],son[maxn][26],mx[maxn],mi[maxn];
  30. int lst=1,cnt=1;
  31. int tax[maxn>>1],a[maxn];
  32. LL c[maxn],t[maxn];
  33. inline void extend(int c,int o) {
  34. int p=++cnt,f=lst;lst=p;
  35. len[p]=len[f]+1,mx[p]=mi[p]=o;
  36. while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
  37. if(!f) {fa[p]=1;return;}
  38. int x=son[f][c];
  39. if(len[f]+1==len[x]) {fa[p]=x;return;}
  40. int y=++cnt;len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
  41. for(re int i=0;i<26;i++) son[y][i]=son[x][i];
  42. while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
  43. }
  44. int main() {
  45. scanf("%d",&n);scanf("%s",S+1);S1.lst=S1.cnt=1;S2.lst=S2.cnt=1;
  46. for(re int i=1;i<=n;i++) S1.ins(S[i]-'a'),pre[i]=S1.tot;
  47. for(re int i=n;i;i--) S2.ins(S[i]-'a'),beh[i]=S2.tot;
  48. memset(mi,20,sizeof(mi));
  49. for(re int i=1;i<=n;i++) extend(S[i]-'a',i);
  50. for(re int i=1;i<=cnt;i++) tax[len[i]]++;
  51. for(re int i=1;i<=n;i++) tax[i]+=tax[i-1];
  52. for(re int i=cnt;i;--i) a[tax[len[i]]--]=i;
  53. for(re int i=cnt;i;--i) {
  54. int x=a[i];
  55. mx[fa[x]]=max(mx[fa[x]],mx[x]);mi[fa[x]]=min(mi[fa[x]],mi[x]);
  56. }
  57. for(re int i=2;i<=cnt;i++) {
  58. if(mi[i]==mx[i]) continue;
  59. int L=mx[i]-len[i]+1,R=mx[i]-len[fa[i]]-1;
  60. if(L<=mi[i]+1) {
  61. L=mi[i]+1;int li=R-L+1;
  62. if(L>R) continue;
  63. t[L]+=li;
  64. t[L+1]+=-1-li;
  65. t[R+2]+=1;
  66. continue;
  67. }
  68. c[mi[i]+1]+=len[i]-len[fa[i]];c[L]-=len[i]-len[fa[i]];
  69. if(len[i]-len[fa[i]]>1) {
  70. if(L>R) continue;
  71. t[L]+=len[i]-len[fa[i]]-1;
  72. t[L+1]+=-len[i]+len[fa[i]];
  73. t[R+2]+=1;
  74. }
  75. }
  76. for(re int i=1;i<=n;i++) t[i]+=t[i-1];
  77. for(re int i=1;i<=n;i++) c[i]+=c[i-1]+t[i];
  78. for(re int i=1;i<=n;i++)
  79. printf("%lld ",pre[i-1]+beh[i+1]-c[i]+(LL)i*(LL)(n-i+1));
  80. puts("");
  81. return 0;
  82. }

「hihocoder1413 Rikka with String」的更多相关文章

  1. [HihoCoder1413]Rikka with String

    vjudge 题意 给你一个串,问你把每个位置的字符替换成#后串中有多少本质不同的子串. \(n\le 3*10^5\) sol 首先可以计算出原串里面有多少本质不同的子串.显然就是\(\sum_{i ...

  2. 【Hihocoder1413】Rikka with String(后缀自动机)

    [Hihocoder1413]Rikka with String(后缀自动机) 题面 Hihocoder 给定一个小写字母串,回答分别把每个位置上的字符替换为'#'后的本质不同的子串数. 题解 首先横 ...

  3. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  4. 「kuangbin带你飞」专题十八 后缀数组

    layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kua ...

  5. 「kuangbin带你飞」专题十七 AC自动机

    layout: post title: 「kuangbin带你飞」专题十七 AC自动机 author: "luowentaoaa" catalog: true tags: - ku ...

  6. 「kuangbin带你飞」专题十二 基础DP

    layout: post title: 「kuangbin带你飞」专题十二 基础DP author: "luowentaoaa" catalog: true tags: mathj ...

  7. 「持续集成实践系列 」Jenkins 2.x 构建CI自动化流水线常见技巧

    在上一篇文章中,我们介绍了Jenkins 2.x实现流水线的两种语法,以及在实际工作中该如何选择脚本式语法或声明式语法.原文可查阅:「持续集成实践系列」Jenkins 2.x 搭建CI需要掌握的硬核要 ...

  8. Socket的用法——NIO包下SocketChannel的用法 ———————————————— 版权声明:本文为CSDN博主「茶_小哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/ycgslh/article/details/79604074

    服务端代码实现如下,其中包括一个静态内部类Handler来作为处理器,处理不同的操作.注意在遍历选择键集合时,没处理完一个操作,要将该请求在集合中移除./*模拟服务端-nio-Socket实现*/pu ...

  9. 「THP3考前信心赛」解题报告

    目录 写在前面&总结: T1 T2 T3 T4 写在前面&总结: \(LuckyBlock\) 良心出题人!暴力分给了 \(120pts\) \(T1\) 貌似是个结论题,最后知道怎么 ...

随机推荐

  1. 个人多年经典收藏集合(SQL) 推荐大家收藏

    1.SQL经典问题 查找连续日期 2.sqlserver 中charindex/patindex/like 的比较 3.SQL Server 跨服务器查询 4.SQLserver中字符串查找功能pat ...

  2. JavaScript call 和apply 的理解

    这两个方法对于一些新手而言难耐弄清他们到底是怎么回事,对我我来讲我对call和apply的方法理解的也比较含糊.今天闲来无事准备彻底搞call和apply到底是怎么回事.本着互联网分享精神.我将我自己 ...

  3. 怎样在ado.net中存取excel和word呢?

    办公软件指可以进行文字处理.表格制作.幻灯片制作.图形图像处理.简单数据库的处理等方面工作的软件.当然啦,这也包括了word.Excel以及PPT等.现在我们就一起来学习一下:怎样在ado.net中存 ...

  4. 项目开发-->基础功能汇总

    祭奠曾经逝去的青春…… 1.基础功能汇总-->身份认证及用户登录模块 2.基础功能汇总-->一键登录功能汇总 3.堆和栈 4.变量

  5. mongodb基本指令

    MongoDB基本命令用成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作. 输入help可以看到基本操作命令: show dbs:显示数据库列表 show co ...

  6. flask之wtforms 表单验证(一)

    一  安装wtforms pip install wtforms 二  导入相关模块及对象 from wtforms import Form, widgets, validators from wtf ...

  7. ubuntu sudo不能用的解决办法

    输入sudo 出现 sudo: /etc/sudoers 可被任何人写 sudo: 没有找到有效的 sudoers 资源,退出 sudo: sudoers的权限被改了 pkexec chmod 044 ...

  8. js原生带缩略图的图片切换效果

    js原生带缩略图的图片切换效果 本例中用到的 moveElement(elementID,final_x,final_y,interval)是来自<JavaScript DOM编程艺术(中文第二 ...

  9. Git Bash Here常用命令以及使用步骤

    1.首先,要clone项目代码: git clone 链接地址 2.更新代码: git pull 3.添加修改过的文件.文件夹: git add 修改过的文件,文件夹 4.提交并注释: git com ...

  10. 微信小程序开发前期准备

    开发文档 官方开发文档 开发IDE 官方工具下载 UI组件 WeUI:是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,新手建议使用: ZanUI-WeAp ...