• CF17E Palisection——优秀的综合计数题


    题意翻译

    给定一个长度为n的小写字母串。问你有多少对相交的回文子 串(包含也算相交) 。 输入格式

    第一行是字符串长度n(1<=n<=2*10^6),第二行字符串 输出格式

    相交的回文子串个数%51123987

    题解

    首先,我们要知道一个串有多少个回文串。

    1.manacher,

    枚举回文中心可以计算出所有的回文串个数

    (i+p[i]-1)-(i-p[i]+1)+1

    然后我们怎么知道多少相交的回文串呢?
    计数问题要转化成有分界点的问题,便于利用乘法加法原理等。——lyd

    这个相交显然不好处理,也没有分界点。

    所以采用容斥。

    2.容斥,所有的回文串对数-不相交的对数

    不相交的话,分界点一下就出来了。我们可以枚举分解点试试。

    因为这样便于划分成区间处理。

    而直接相交处理不容易。

    3.枚举分界点统计

    c[x][0]以x开始的回文串个数,c[x][1]以x为末尾的回文串个数

    这两个可以区间加,差分处理。

    具体来说,一个点为中心的所有回文串,会给(i-p[i]+1)~(i)位置开始的回文串多一个。c[x][1]同理。

    这里的差分,不用树状数组....并不需要动态维护修改查询

    直接数组差分即可。最后从左到右累加,一边统计c[x][0/1]

    然后令,pre[x],为c[x][1]的前缀和

    对于枚举的分界点i(2<=i<=n) ,ans-=pre[i-1]*c[i][0]

    根据回文串开始和结束位置的唯一性,这样一定不重不漏。

    相当于把每个字符串和前面不相交的字符串都统计了一遍。

    代码:注意%=mod

    #include<bits/stdc++.h>
    #define ri register int
    #define il inline
    using namespace std;
    typedef long long ll;
    const int N=2000000+5;
    const int mod=51123987;
    int n,m;
    int p[2*N];
    char a[N],b[2*N];
    il void manacher(){
        p[1]=1;
        int mx=1,id=1;
        for(ri i=2;i<=m;i++){
            p[i]=min(p[2*id-i],mx-i);
            if(p[i]<1) p[i]=1;
            int j=i-p[i],k=i+p[i];
            while(j>=1&&k<=m&&b[j]==b[k]){
                p[i]++;
                j--;k++;
            }
            if(i+p[i]-1>mx){
                mx=i+p[i]-1;
                id=i;
            }
        }
    }
    ll f[N],g[N];
    ll ans,tot,sum;
    ll c[N][2],pre[N];
    il void add1(int x,ll c){
        f[x]+=c;
    }
    il void add2(int x,ll c){
        g[x]+=c;
    }
    signed main()
    {
        scanf("%d",&n);
        scanf("%s",a+1);
        b[++m]='#';
        for(ri i=1;i<=n;i++){
            b[++m]=a[i];
            b[++m]='#';
        }
        manacher();
        for(ri i=1;i<=m;i++){
            if(i&1) (tot+=p[i]/2)%=mod;//%mod;//#
            else (tot+=p[i]/2)%=mod;//%mod;//not        
        }
        ans=(tot*(tot-1)/2)%mod;//%mod;
        for(ri i=1;i<=n;i++){
            add1(i-p[i*2]/2+1,(ll)1),add1(i+1,(ll)-1);
            if(i!=n) add1(i-p[i*2+1]/2+1,(ll)1),add1(i+1,(ll)-1);
            
        }
        
        for(ri i=1;i<=n;i++){
            c[i][0]=(c[i-1][0]+f[i])%mod;
        }
        
        for(ri i=1;i<=n;i++){
            add2(i,(ll)1),add2(i+(p[i*2]/2),(ll)-1);
            if(i!=n) add2(i+1,(ll)1),add2(i+p[i*2+1]/2+1,(ll)-1);
        }pre[0]=0;
        for(ri i=1;i<=n;i++){
            c[i][1]=(c[i-1][1]+g[i])%mod;
            pre[i]=(pre[i-1]+c[i][1])%mod;
            if(i>=2){
                ll now=(pre[i-1]*c[i][0])%mod;
                ans=(ans+mod-now)%mod;
            }
        }
        printf("%lld",ans);
        return 0;
    }

    总结:

    突破口:容斥。划分分界点统计。

  • 相关阅读:
    android ListView布局之一(继承listActivity、使用arrayAdapter)
    android your project contains error
    wojilu系统的ORM代码解析[源代码结构分析,ObjectBase基类分析]
    ORM中启用数据库事务
    我记录网站综合系统 技术原理解析[11:ActionProcessor流程wojilu核心]
    互联网,让我们更安全了,还是更危险了【纯讨论】
    不用服务器也能跑的框架wojilu续篇
    使用wojilu 无代码实现 输入框提示 及其背后的原理
    wojilu日志系统可以单独使用
    “我有什么” 和 “你要什么” 框架制作的一些思考
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9688595.html
Copyright © 2020-2023  润新知