zoukankan      html  css  js  c++  java
  • [ CodeForces 17 E ] Palisection

    (\​)

    (Description)


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

    • (Nin [1,2 imes 10^6])

    (\)

    (Solution)


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

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

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

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

    (\)

    (Code)


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 2000010
    #define R register
    #define gc getchar
    #define mod 51123987
    using 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
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    MySQL数据库“局部”乱码
    每个人都可以写博客
    命令行导入SQL文件
    数据库连接扩展
    PHP程序设计经典300例
    C# 调用外部dll
    asp.net中实现文件下载功能
    Windows10下Docker的安装
    java基础——面向对象
    java基础——第一章概述
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9690121.html
Copyright © 2011-2022 走看看