Palisection(CF-17E) - 竞赛题解

Manacher学到一定程度,也需要练一下有趣的题了……

(这是多老的题了 \(QwQ\))〔传送门〕


『题意』

给出一个字符串,求总共有多少对不同的(只要位置不同)回文子串有重叠。

举个例子(样例):"babb"

有 "bab"(0~2) , "b"(0) , "a"(1) , "b"(2) , "b"(3) , "bb"(2~3) 是回文子串,其中 (0~2) 与 (0),(1),(2),(2~3) 都有重叠,(2~3) 与 (2),(3) 有重叠,因此总共 6 对;

(我希望我翻译得比较正确)


『题解』

首先看到回文子串,我们可以用Manacher算法以 \(O(n)\) 的复杂度[1]求出以每个位置为中心的最长的回文子串。但是根据题目意思,可以发现它是求的所有的回文子串(例如Manacher算法可以求出较长的回文子串"abba",但题目要求的是同时求得 "abba","bb"),因此我们需要根据求出的较长回文子串推导出所有的回文子串:

令长度为 \(len\),回文子串的左右端点分别为\(lef,rig\),中点 \(mid=\left \lfloor \frac{lef+rig}{2} \right \rfloor\),定义 \([a,b](a<b)\) 表示位置从a到b的子串

  1. 对于len为奇数,则会有回文子串 \([lef,rig]、[lef+1,rig-1]、...、[mid,mid]\);
  2. 对于len为偶数,则会有回文子串 \([lef,rig]、[lef+1,rig-1]、...、[mid,mid+1]\);

这样就可以把所有的回文子串都求出来了(而且恰好不重复)。

接下来就需要求有哪些相交……但是显然求相交的子串个数不如求不相交的子串个数——那么根据简单的“容斥”[2],我们就可以求出答案。

(让我们先忽略题目中的“无序数对”,假设两个串的顺序是有影响的,即 A与B有重叠 ≠ B与A有重叠)

那么我们可以通过上面的方法求出总共有多少个回文子串,记为 \(tot\),那么总共就有 \(tot*(tot-1)\) 对字符串。

然后计算有多少对是不重叠的。不重叠有两种情况:① 一个串的右端点在另一个串左端点的左边;②一个串的左端点在另一个串的右端点的右边

容易想到对于每个点,存储以它结尾以及以它开始的回文子串的个数,分别记为 ovr[],beg[]。那么我们就可以先从左到右扫描,得出结束位置小于当前位置的回文子串个数,再乘上以当前位置开始的回文子串的个数(组合数学的乘法原理)就是“右端点在左端点左边”的情况。反过来求“左端点在右端点右边”的情况也是一样的。

然后就剩下求 ovr[] 和 beg[] 的问题了。实际上在Manacher算法中每找到一个以当前位置为中心的最长回文子串\([lef,rig]\):

如果 \(len\) 是奇数,则 ovr[mid~rig]++,beg[lef,mid]++;

如果 \(len\) 是偶数,则 ovr[(mid+1)~rig]++,beg[lef,mid]++;

可见这是一个区间加和的问题……线段树?其实没有必要,可以直接用差分数组解决。

差不多就这样了,具体差分数组的实现以及其他的小细节留给reader们思考了~

(提示一下:如果你发现你WA在第 27 组数据,大概是你没有注意到逆元这个东西)


『源代码』

/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int SIZ=int(2e6);
const long long MOD=51123987ll,INV=(MOD+1)/2;
int len_str,len_mdy;
char str[SIZ+7],mdy[2*SIZ+7];
int haf[2*SIZ+7];
long long beg[SIZ+7],ovr[SIZ+7];
long long Manacher(){
int RIG=0,MID=0;
long long tot=0;
for(int i=1;i<len_mdy;i++){
if(i<RIG) haf[i]=min(haf[2*MID-i],RIG-i);
else haf[i]=1;
while(mdy[i-haf[i]]==mdy[i+haf[i]]) haf[i]++;
if(i+haf[i]>RIG) RIG=i+haf[i],MID=i;
int lef=(i-haf[i])/2,len=haf[i]-1,rig=lef+len-1,mid;
if(!len) continue;
if(len%2){ //01234 len=5
mid=lef+len/2;
ovr[mid]++;ovr[rig+1]--;
beg[lef]++;beg[mid+1]--;
tot+=len/2+1;
}
else{ //0123 len=4
mid=lef+len/2-1;
ovr[mid+1]++;ovr[rig+1]--;
beg[lef]++;beg[mid+1]--;
tot+=len/2;
}
tot%=MOD;
}
for(int i=0;i<len_str;i++){
beg[i]%=MOD;ovr[i]%=MOD;
ovr[i+1]+=ovr[i],beg[i+1]+=beg[i];
}
long long del=0,cnt=0;
for(int i=0;i<len_str;i++){
del=(del+beg[i]*cnt)%MOD;
cnt+=ovr[i];
cnt%=MOD;
}
cnt=0;
for(int i=len_str-1;i>=0;i--){
del=(del+ovr[i]*cnt)%MOD;
cnt+=beg[i];
cnt%=MOD;
}
tot=(tot+MOD-1)%MOD*tot%MOD;
tot=tot*INV%MOD;del=del*INV%MOD;
return (tot+MOD-del%MOD)%MOD;
}
int main(){
scanf("%d%s",&len_str,str);
len_mdy=len_str*2+2;
mdy[0]='+';mdy[1]='|';
for(int i=0;i<len_str;i++)
mdy[2*i+2]=str[i],mdy[2*i+3]='|';
long long res=Manacher();
printf("%lld\n",res);
return 0;
}

\(\mathcal{The\ End}\)

\(\mathcal{Thanks\ For\ Reading!}\)

(各位reader有什么不懂的在邮箱里面问嘛 - \(lucky\_glass@foxmail.com\))


  1. 这里说的是平摊下来 ↩︎

  2. 并不是真正的容斥原理,只是“全集-补集”而已 ↩︎

竞赛题解 - Palisection(CF-17E)的更多相关文章

  1. 竞赛题解 - CF Round #524 Div.2

    CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...

  2. 竞赛题解 - [CF 1080D]Olya and magical square

    Olya and magical square - 竞赛题解 借鉴了一下神犇tly的博客QwQ(还是打一下广告) 终于弄懂了 Codeforces 传送门 『题目』(直接上翻译了) 给一个边长为 \( ...

  3. 《ACM国际大学生程序设计竞赛题解Ⅰ》——基础编程题

    这个专栏开始介绍一些<ACM国际大学生程序设计竞赛题解>上的竞赛题目,读者可以配合zju/poj/uva的在线测评系统提交代码(今天zoj貌似崩了). 其实看书名也能看出来这本书的思路,就 ...

  4. 竞赛题解 - Karp-de-Chant Number(BZOJ-4922)

    Karp-de-Chant Number(BZOJ-4922) - 竞赛题解 进行了一次DP的练习,选几道题写一下博客~ 标签:BZOJ / 01背包 / 贪心 『题目』 >> There ...

  5. 竞赛题解 - Broken Tree(CF-758E)

    Broken Tree(CF-758E) - 竞赛题解 贪心复习~(好像暴露了什么算法--) 标签:贪心 / DFS / Codeforces 『题意』 给出一棵以1为根的树,每条边有两个值:p-强度 ...

  6. 竞赛题解 - NOIP2018 保卫王国

    \(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...

  7. 竞赛题解 - NOIP2018 旅行

    \(\mathcal {NOIP2018} 旅行 - 竞赛题解\) 坑还得一层一层的填 填到Day2T1了 洛谷 P5022 题目 (以下copy自洛谷,有删减/修改 (●ˇ∀ˇ●)) 题目描述 小 ...

  8. 竞赛题解 - NOIP2018 赛道修建

    \(\mathcal {NOIP2018}\) 赛道修建 - 竞赛题解 额--考试的时候大概猜到正解,但是时间不够了,不敢写,就写了骗分QwQ 现在把坑填好了~ 题目 (Copy from 洛谷) 题 ...

  9. 竞赛题解 - Ikki's Story IV-Panda's Trick

    Ikki's Story IV-Panda's Trick - 竞赛题解 也算是2-sat学习的一个节点吧 终于能够自己解决一道2-sat的题了 ·题目 一个圆上有n个点按顺时针编号为 0~n-1 , ...

随机推荐

  1. jQuery框架学习第十一天:实战jQuery表单验证及jQuery自动完成提示插件

    jQuery框架学习第一天:开始认识jQueryjQuery框架学习第二天:jQuery中万能的选择器jQuery框架学习第三天:如何管理jQuery包装集 jQuery框架学习第四天:使用jQuer ...

  2. Infor SyteLine如何快速锁定用户

    使用Infor Syteline ERP系统,当需要做系统维护时,我们需要通知所有用户退出系统,在维护期间,严禁用户登录,这样的话,我们需要锁定用户.对于这个问题,很多管理员会打开SL的Users窗口 ...

  3. Mysql存储Emoji表情[为何utf8不能存储以及如何使Mysql能够存储Emoji表情]

    https://segmentfault.com/a/1190000008533577

  4. SVNKit学习——Setting Up A Subversion Repository 创建仓库(三)

    所谓Setting Up A Subversion Repository,就是在Subversion所在的服务器上创建一个仓库,说白了就是在磁盘上建一个特殊的目录,这里我以windows举例. 1.使 ...

  5. Routing Manager for WCF4 z

    http://www.codeproject.com/Articles/77198/Routing-Manager-for-WCF Download source Contents Features ...

  6. mysql io过高

    背景: 晚上,公司业务群里发信息说,有玩家在游戏里面赠送别人礼物后,赠送记录在20多分钟以后才出现,延时太高. 问题: 公司数据库使用mysql,配置了主从.配置的是,游戏程序写数据到主库,读数据到从 ...

  7. 使用mysli防止sql注入

    自从 php5 推出 mysqli 后就开始不提倡使用 mysql_ 开头的接口了,现在使用 mysql_connet 通常调试的时候会报警告说这个不该用 mysqli 使用起来其实更简单 $url ...

  8. oracle获得ddl语句

    dbms_metadata.get_ddl()用于获取对象的DDL,其具体用法如下.注意:在sqlplus里,为了更好的展示DDL,需要设置如下参数:set line 200set pagesize ...

  9. webpack学习(四)extract-text-webpack-plugin插件

    二.extract-text-webpack-plugin插件 从 bundle 中提取文本(CSS)到单独的文件 安装 npm install extract-text-webpack-plugin ...

  10. java学习第一步,使用IntelliJ IDEA编写自己的第一个java程序

    首先下载java的jdk,然后说一下IDEA的配置 IntelliJ IDEA目前公认的最好的java开发工具,不过一般的学校的教学还是使用eclipse来进行java的开发.所以老师一般只会教你如何 ...