• HDU 5785 Interesting manacher + 延迟标记


    题意:给你一个串,若里面有两个相邻的没有交集的回文串的话,设为S[i...j] 和 S[j+1...k],对答案的贡献是i*k,就是左端点的值乘上右端点的值。

    首先,如果s[x1....j]、s[x2....j]、s[x3....j]....s[xn....j]、是回文串,而且s[j+1...y1]、s[j+1...y2]、s[j+1...y3]、也是回文串,那么这些串对答案的贡献一共就是(x1+x2+...+xn)*(y1+y2+....+yn)

    所以想到了用cntL[i]表示:以i这个字符为结尾的回文串的左端点之和,cntR[i]表示:以i这个字符为开始的回文串的右端点之和。

    所以答案就是for i=1 to lenstr-1  ans += cntL[i]*cntR[i+1];

    通俗点说吧,根据manacher,p[i]就表示以i这个字符为中心的回文串的半径长度,所以有s[i-p[i]...i+p[i]]是一个回文串

    所以cntL[i+p[i]]就要加上i-p[i],然后因为s[i-p[i]+1...i+p[i]-1]也是一个回文串,所以cntL[i+p[i]-1]就要加上i-p[i]+1等等之类的。所以就是在[i..i+p[i]]这个区间上,依次加上 i、i-1、i-2、.....i-p[i],这样一个公差为-1的等差数列。这个可以用延迟标记来做

    先看简单的,在[L,R]上加上一个数val,我们只需要cnt[L] += val; cnt[R+1] -= val;   然后O(n)扫描,即可得到这个数组的所有值。但是现在是等差数列呢?其实是差不多的,只不过要开多一个数组而已。

    首先,如果是在[begin,end]上加上一个以val为首相的等差数列,可以这样考虑。首先cnt[begin] += val;然后可以算出结束的时候的值是多少把?cnt[end+1] -= calc_end_val;即可。然后中间的公差,因为可能有叠加现象,我们要开多个数组subL[i]表示这个位置有多少个-1,这个subL[i]就像一开始的最简单的这样传递下去即可。就是subL[begin] += 1; subL[end+1] -= 1;

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include<stack>
    #include <string>
    const int maxn = 1000000+20;
    const int MOD = 1000000007;
    int cntL[maxn],cntR[maxn];
    int subL[maxn],subR[maxn];
    char str[maxn<<1];
    int p[maxn<<1];
    void addL (int begin,int end,int val)
    {
        if (end<begin) return ;
        cntL[begin] += val;
        cntL[end+1] -= begin-end+val;
        subL[begin+1]++;
        subL[end+1]--;
    
        cntL[begin] %= MOD;
        cntL[end+1] = (cntL[end+1]+MOD)%MOD;
        subL[begin+1]%=MOD;
        subL[end+1]=(subL[end+1]+MOD)%MOD;
        return ;
    }
    void addR (int begin,int end,int val)
    {
        if (end<begin) return ;
        cntR[begin] += val;
        cntR[end+1] -= begin-end+val;
        subR[begin+1]++;//记录有多少个数列覆盖的,记录公差
        subR[end+1]--;
    
        cntR[begin] %= MOD;
        cntR[end+1] = (cntR[end+1]+MOD)%MOD;
        subR[begin+1]%=MOD;
        subR[end+1]=(subR[end+1]+MOD)%MOD;
        return ;
    }
    int manacher (char str[],int lenstr)
    {
        str[0]='*';
        for (int i=lenstr;i>=0;i--)
        {
            str[i+i+2]=str[i+1];
            str[i+i+1]='#';
        }
        int id=0,maxlen=0;
        for (int i=2;i<=2*lenstr+1;i++)
        {
            if (p[id]+id>i)
            {
                p[i]=min(p[id]+id-i,p[2*id-i]);
            }
            else p[i]=1;
            while (str[i+p[i]] == str[i-p[i]]) ++p[i];
            if (p[id]+id<p[i]+i) id=i;
            maxlen=max(maxlen,p[i]);
        }
        return maxlen-1;
    }
    
    void init_arr(int gg)
    {
        for (int i=1;i<=gg;++i)
        {
            subL[i] += subL[i-1];
            cntL[i] += cntL[i-1]-subL[i];
    
            subR[i] += subR[i-1];
            cntR[i] += cntR[i-1]-subR[i];
    
            subL[i] %= MOD;  subR[i] %= MOD;
            cntL[i]=(cntL[i]+MOD)%MOD; cntR[i]=(cntR[i]+MOD)%MOD;
        }
        return ;
    }
    void init ()
    {
        memset(cntL,0,sizeof cntL); memset(cntR,0,sizeof cntR);
        memset(subL,0,sizeof subL); memset(subR,0,sizeof subR);
        return ;
    }
    void work ()
    {
        init();
        int lenstr = strlen(str+1);
        manacher(str,lenstr);
        for (int i=2;i<=2*lenstr+1;++i)
        {
            int len = p[i]-1;
            if (len==0) continue;
            if (i&1) //'#'所在位置
            {
                int pos = i/2;//截断
                //len必须是偶数
                int t = len/2;
                int begin = pos-t+1; //这些细节要慢慢算啦,慢慢推公式
                int end = t+pos;
                addL(pos+1,end,pos);
                addR(begin,pos,end);
            }
            else //字母所在位置
            {
                int pos = i/2;
                len--;
                len/=2;
                int begin = pos-len;
                int end = pos+len;
                addL(pos,end,pos);
                addR(begin,pos,end);
            }
        }
        init_arr(lenstr);
        LL ans = 0;
        for (int i=1;i<=lenstr-1;++i)
        {
            ans += 1LL*cntL[i]*cntR[i+1];
            ans %= MOD;
        }
        printf ("%I64d
    ",ans);
        return ;
    }
    int main ()
    {
        #ifdef local
        freopen("data.txt","r",stdin);
        #endif
        while(scanf("%s",str+1)!=EOF) work();
        return 0;
    }
    View Code
  • 相关阅读:
    ASPNET下的路径辅助类
    分析函数计算起始,结束日期.
    Debugging SQL Server 2005 Stored Procedures in Visual Studio
    Storing Binary Files Directly in the Database Using ASP.NET 2.0
    Fw:Managing View State in ASP.NET 4 Using the New ViewStateMode Property
    Using ASP.NET 3.5's ListView and DataPager Controls: Displaying Data with the ListView
    Passing Information Between Content and Master Pages .
    转:Querying a Hierarchical ParentChild Structure in LINQ
    续上篇:比较彻底的清除"代理木马下载器"的方法
    面向过程和面向对象--从C到C#
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5782177.html
Copyright © 2020-2023  润新知