博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[ CodeForces 17 E ] Palisection
阅读量:5030 次
发布时间:2019-06-12

本文共 1793 字,大约阅读时间需要 5 分钟。

\(\\​\)


给定一个长度为\(N\)的小写字母串。问有多少对相交的回文子串\((\)包含也算相交\()\),答案对\(51123987\)取模。

  • \(N\in [1,2\times 10^6]\)

\(\\\)

\(Solution\)


  • 先考虑相交如何处理。因为相交既跟端点有关,又跟长度有关,回文子串数目众多不好处理。正难则反。假设总回文串个数是\(cnt\)个,如果两两都相交一共有\(\frac{cnt\times(cnt-1)}{2}\)对,所以答案就是\(\frac{cnt\times(cnt-1)}{2}-\)不相交回文子串对数。

  • 先考虑处理回文串个数回文串个数。在\(Manacher\)时可以直接求出,因为每一个长的回文串一定包含着若干个共同回文中心的回文子串,所以一个位置带来的回文串数就是这一位置的回文半径长度\((\)还原后\()\)

  • 在考虑处理不相交对数。统计以每一个位置为左端点和右端点的回文子串个数,根据端点处理。一个直接的想法是对每一个位置直接累加,右端点在它左边的子串数\(\times\)左端点在它右边的子串数,但这种方法显然会算重很多部分。考虑固定一侧,即确定左端点必须在这一位置,让这个子串数乘上右端点在它左边的子串数累加出来的答案,是不重不漏的,其中第二项做的时候可以前缀和处理。

  • 关于以每一个开始和结束的回文子串数量,每求出一个位置暴力累加所有子串复杂度显然过不了。考虑差分。因为新加入的子串开头的位置一定是一段连续的区间,从最左的端点一直到回文中心,而结束的也是同理。最后对两个数列分别求一下前缀和就好,注意跟上一条结合在一起,右端点的数列会在计算过程中求两遍前缀和,即最后得到的是原数列的前缀和。

\(\\\)

\(Code\)


#include
#include
#include
#include
#include
#include
#include
#define N 2000010#define R register#define gc getchar#define mod 51123987using namespace std;typedef long long ll;char c,s[N<<1];ll ans;int n,p,mr,slen,l[N<<1],r[N<<1],len[N<<1];inline void init(){ scanf("%d",&n); while(!isalpha(c=gc())); s[1]=s[slen=3]='#'; s[2]=c; for(R int i=2;i<=n;++i){s[++slen]=gc();s[++slen]='#';} s[0]='['; s[slen+1]=']';}inline void manacher(){ for(R int i=1,p=0,mr=0;i<=slen;++i){ len[i]=(i>mr)?1:min(mr-i+1,len[(p<<1)-i]); while(s[i-len[i]]==s[i+len[i]]) ++len[i]; if(i+len[i]-1>mr){mr=i+len[i]-1;p=i;} ++l[i-len[i]+1]; --l[i+1]; ++r[i]; --r[i+len[i]]; (ans+=(ll)(len[i]>>1))%=mod; } ans=(ans*(ans-1)/2)%mod;}int main(){ init(); manacher(); for(R int i=1,sum=0;i<=slen;++i){ l[i]+=l[i-1]; r[i]+=r[i-1]; if(i%2==0){ ans=(ans-(ll)l[i]*sum%mod+mod)%mod; (sum+=r[i])%=mod; } } printf("%lld\n",ans); return 0;}

转载于:https://www.cnblogs.com/SGCollin/p/9690121.html

你可能感兴趣的文章
一个自己写的判断2个相同对象的属性值差异的工具类
查看>>
10 华电内部文档搜索系统 search03
查看>>
[HIHO1149]回文字符序列(dp)
查看>>
[HDU1402]A * B Problem Plus(FFT)
查看>>
[CF803C] Maximal GCD(gcd,贪心,构造)
查看>>
逆时针旋转的矩阵变换
查看>>
第10周15/16/17
查看>>
【数据库】SQL两表之间:根据一个表的字段更新另一个表的字段
查看>>
四六级作文常见错误解析(转载)
查看>>
Tomcat
查看>>
./是当前目录 ../是当前的上一级目录。上上级就是../../一般绝对路径时候常用...
查看>>
linux支持FTP和SFTP服务【1】
查看>>
树的递归与非递归遍历方法
查看>>
每天一个Linux命令(6):rmdir命令
查看>>
oracle连接的三个配置文件(转)
查看>>
Vim配置文件(Vimrc)
查看>>
RecyclerView 局部刷新(获取viewHolder 去刷新)
查看>>
PHP表单(get,post)提交方式
查看>>
使用vbs或者bat脚本修改IE浏览器安全级别和选项
查看>>
Silverlight入门
查看>>