zoukankan      html  css  js  c++  java
  • CC 3-Palindromes(manacher)

    传送门:3-Palindromes

    题意:求为回文串且能整除3且不前导0的子串个数。

    分析:由 manacher算法O(N)可算出以i为坐标的最长为p[i]回文子串,且Si-k,Si-k+1......Si+k-1,Si+k(0<k<p[i])全为回文串。

    又知,能整除3的整数数位和也能整除3,那么只要Si-k,Si-k+1......Si+k-1,Si+k和整除3即可。

    由回文串对称性知Si-k==Si-k,那么只要Si-k..Si-1这段中模3余数与Si模3余数相同,Si-k...Si+k和必定整除3(设左右各位余数x+本身x=3x).

    因此只要预处理出Si...Sj整段中模3余0,1,2的个数,就可O(N)得出全部符合条件的子串。

    #pragma comment(linker,"/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <limits.h>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstdlib>
    #include <stack>
    #include <vector>
    #include <set>
    #include <map>
    #define LL long long
    #define mod 1000000007
    #define inf 0x3f3f3f3f
    #define eps 1e-6
    #define N 1000010
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define PII pair<int,int>
    using namespace std;
    inline LL read()
    {
        char ch=getchar();LL x=0,f=1;
        while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int p[N<<1],len,num,mx,id;
    char s[N],str[N<<1];
    void build()
    {
        len=strlen(s);num=0;
        str[num++]='@';str[num++]='#';
        for(int i=0;i<len;i++)
        {
            str[num++]=s[i];
            str[num++]='#';
        }
        str[num]=0;
    }
    void manacher()
    {
        mx=0;
        memset(p,0,sizeof(p));
        for(int i=1;i<num;i++)
        {
            if(mx>i)p[i]=min(p[2*id-i],mx-i);
            else p[i]=1;
            while(str[i-p[i]]==str[i+p[i]])p[i]++;
            if(p[i]+i>mx)mx=p[i]+i,id=i;
        }
    }
    int a[N<<1],sum[N<<1][3];
    void solve()
    {
        for(int i=2;i<num;i++)
        {
            a[i]=a[i-1];//前缀和
            if(str[i]!='#')a[i]=(a[i]+str[i]-'0')%3;
            for(int j=0;j<3;j++)sum[i][j]=sum[i-1][j];
            if(str[i]!='#'&&str[i]!='0')
            sum[i][a[i]]++;
        }
        LL ans=0;
        for(int i=2;i<num;i++)
        {
            int t=(str[i]-'0')%3;
            if(str[i]=='#')t=0;
            if(str[i]!='#'&&t==0)ans++;
            int k=(t+a[i])%3;//由于sum[i+p[i]-1][k]~sum[i][k]都多了a[i],因此补回来防止误差
            ans+=sum[i+p[i]-1][k]-sum[i][k];
        }
        printf("%lld
    ",ans);
    }
    int main()
    {
        while(scanf("%s",s)>0)
        {
            build();
            manacher();
            solve();
        }
    }
    View Code
  • 相关阅读:
    数论
    2019牛客暑期多校训练营(第七场)
    C++大数模板
    网络流
    2019 Multi-University Training Contest 6
    无聊的数列
    Can you answer on these queries III
    Interval GCD
    2733:判断闰年-poj
    题目1083:特殊乘法-九度oj
  • 原文地址:https://www.cnblogs.com/lienus/p/4299947.html
Copyright © 2011-2022 走看看