zoukankan      html  css  js  c++  java
  • HDU 5785 Interesting

    题目:

    大概说给一个字符串,找到其所有子串[i...k]满足它是由两个回文串拼成的,求Σi*k。

    分析:

    用val[1][i]表示以i结尾的回文串的起始位置的和val[0][i]表示以i起始的回文串的结尾位置的和,然后就可以求出答案了. Σ(val[1][i]*val[0][i+1])就是答案.

    1.假设原串为a[]={aaa},使用manacher算法将原串变为#a#a#a#,对应的p数组为{1,2,3,4,3,2,1}.p[i]/2-1的值为新串中以i为中心的回文半径.(回文串长度为奇数,即a[i]!=’#’);p[i]/2的值为新串中以i为中心的回文半径(回文串长度为偶数,即a[i]==’#’&&p[i]!=1)

    2.比如当前回文串的中间位置是i(回文串是奇数的情况,偶数同理),p[i]表示Manacher求得的延伸半径。那么[i-p[i]+1, i+p[i]-1]就是回文串,故val[1][i+p[i]-1]就该加上i-p[i]+1;而[i-p[i]+2, i+p[i]-2]也是回文串,val[1][i+p[i]-2]就该加上i-p[i]+2…………总之可以知道这个就相当于,对于val[1]数组要在[i, i+p[i]-1]区间上依次加上一个末项为i-p[i]+1且公差为-1的等差数列,val[0]也是同理的这儿同样就不说了。

    2.接下来的问题就是如何对对区间更新,让区间[L,R]加上一个首项k公差-1的等差数列。想到了加标记addtag表示加多少。上述问题就转化为addtag[L]+=k;addtag[L+1]+=addtag[L]-1; 考虑到多个区间修改有叠加,开addcnt表示各个点有多少个加操作。所以addtag[L+1]+=addtag[L]-addcnt[L];addcnt[L+1]+=addcnt[L];有余这样的传递会一直传递到数组尾巴,相当于更新了[L,MAXN]区间,所以要减去[R+1,MAXN]区间的(显然也是一个等差数列)。于是用subtag和subcnt表示.处理方式同addtag和addcnt

    输入:

    aaa
    abc

    输出:

    14
    8

    代码:

    #include <iostream>

    #include <cstdio>

    #include <cstdlib>

    #include <cmath>

    #include <vector>

    #include <queue>

    #include <cstring>

    #include <string>

    #include <algorithm>

    using namespace std;

    const int maxn=1111111;

    const int mod=1000000007;

    char s[maxn<<1];

    int p[maxn<<1];//p[i]存放以i为中心最长的回文串长度+1

    void manacher()

    {

        int mx=0,id;

        for(int i=1;s[i];i++)

        {

            if(mx>i)

                p[i]=min(p[2*id-1],mx-1);

            else

                p[i]=1;

            for(;s[i+p[i]]==s[i-p[i]];++p[i]);

            if(p[i]+i>mx)

            {

                mx=p[i]+1;

                id=1;

            }

        }

    }

    char str[maxn];

    long long val[2][maxn];//val[0][i]代表以i起始的回文串的结尾位置的和,val[1][i]表示以i结尾的回文串的起始位置的和

    long long addtag[2][maxn],addcnt[2][maxn],subtag[2][maxn],subcnt[2][maxn];

    void update(int flag,int l,int r,int k)//flag为0处理val[0],为1处理val[1];

    {

        addtag[flag][l]+=k;

        addtag[flag][l]%=mod;

        ++addcnt[flag][l];

        subtag[flag][r+1]+=k-r+l;

        subtag[flag][r+1]%=mod;

        ++subcnt[flag][r];

    }

    void pushdown()

    {

        for(int i=1;str[i];i++){

            if(addcnt[0][i]){

                val[0][i]+=addtag[0][i];

                val[0][i]%=mod;

                addtag[0][i+1]+=addtag[0][i]-addcnt[0][i];

                addtag[0][i+1]%=mod;

                addcnt[0][i+1]+=addcnt[0][i];

            }

            if(subcnt[0][i]){

                val[0][i]-=subtag[0][i];

                val[0][i]%=mod;

                subtag[0][i+1]+=subtag[0][i]-subcnt[0][i];

                subtag[0][i+1]%=mod;

                subcnt[0][i+1]+=subcnt[0][i];

            }

            if(addcnt[1][i]){

                val[1][i]+=addtag[1][i];

                val[1][i]%=mod;

                addtag[1][i+1]+=addtag[1][i]-addcnt[1][i];

                addtag[1][i+1]%=mod;

                addcnt[1][i+1]+=addcnt[1][i];

            }

            if(subcnt[1][i]){

                val[1][i]-=subtag[1][i];

                val[1][i]%=mod;

                subtag[1][i+1]+=subtag[1][i]-subcnt[1][i];

                subtag[1][i+1]%=mod;

                subcnt[1][i+1]+=subcnt[1][i];

            }

        }

    }

    int main()

    {

        while(~scanf("%s",str+1))

        {

            s[0]='$';

            int i=1;

            for(;str[i];i++)

            {

                s[(i<<1)-1]='#';

                s[i<<1]=str[i];

            }

            s[(i<<1)-1]='#';

            s[i<<1]=0;

            manacher();

    //        for(int i=1;s[i];i++)

    //            cout<<p[i]<<" "<<s[i]<<endl;

            memset(val,0,sizeof(val));

            memset(addtag,0,sizeof(addtag));

            memset(addcnt,0,sizeof(addcnt));

            memset(subtag,0,sizeof(subtag));

            memset(subcnt,0,sizeof(subcnt));

            for(int i=1;s[i];i++)

            {

                if(i&1){//处理回文串长度为偶数的情况

    //                cout<<s[i]<<endl;

                    if(p[i]/2==0)

                        continue;

                    update(0, i/2-p[i]/2+1, i/2, i/2+p[i]/2);

                    update(1, i/2+1, i/2+p[i]/2, i/2);

                }

                else{//处理回文串长度为奇数的情况

                    update(0, i/2-p[i]/2+1, i/2, i/2+p[i]/2-1);

                    update(1, i/2, i/2+p[i]/2-1, i/2);

                }

            }

            pushdown();

            long long ans=0;

            for(int i=1;str[i]&&str[i+1];i++){

                //cout<<i<<endl;

                ans+=val[1][i]*val[0][i+1];

                ans%=mod;

            }

            if(ans<0)

                ans+=mod;

            printf("%lld ",ans);

        }

    }

  • 相关阅读:
    什么是电信BOSS系统?
    得到windows系统图标的解决方案
    FusionChart实现金字塔分布图
    OCP-1Z0-051-V9.02-91题
    FusionChart用XML和JSON两种格式提供数据源
    OCP-1Z0-051-V9.02-156题
    OCP-1Z0-051-V9.02-155题
    OCP-1Z0-051-V9.02-154题
    OCP-1Z0-051-V9.02-153题
    OCP-1Z0-051-V9.02-151题
  • 原文地址:https://www.cnblogs.com/137033036-wjl/p/5745846.html
Copyright © 2011-2022 走看看