CF17E Palisection

一、題目

點此看題

二、解法

正難則反,用全部減去不交即可得到相交的情況數。

先跑一遍manachermanacher,可以差分出以每個位置開始和結束迴文串數量,然後我們掃一遍,用前面rr的和乘上當前的ll計入貢獻,注意我們只需要統計#號位置處的貢獻。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 4000005;
const int MOD = 51123987;
#define ll long long
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,p[M],l[M],r[M];char s[M],t[M];
ll qkpow(ll a,int b)
{
    ll res=1;
    while(b>0)
    {
        if(b&1) res=res*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return res;
}
signed main()
{
    n=read();
    scanf("%s",s);
    for(int i=0;i<n;i++)
    {
        t[2*i+1]=s[i];
        t[2*i]='#';
    }
    t[2*n]='#';
    n=2*n+1;
    int c=0,R=0;
    for(int i=0;i<n;i++)
    {
        p[i]=R>i?min(p[2*c-i],R-i+1):1;
        while(i+p[i]<n && i-p[i]>=0 && t[i+p[i]]==t[i-p[i]])
            p[i]++;
        if(i+p[i]>R)
        {
            R=i+p[i]-1;
            c=i;
        }
    }
    ll ans=0,s=0;
    for(int i=0;i<n;i++)
    {
        l[i-p[i]+1]++;l[i+1]--;
        r[i]++;r[i+p[i]]--;
        ans=(ans+p[i]/2)%MOD;
    }
    ans=ans*(ans-1)/2%MOD;
    for(int i=0;i<n;i++)
    {
        l[i]+=l[i-1];r[i]+=r[i-1];
        if(i%2) ans=(ans-s*l[i])%MOD,s=(s+r[i])%MOD;
    }
    printf("%lld\n",(ans%MOD+MOD)%MOD);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章