ACdreamoj 1011(树状数组维护字符串hash前缀和)

Posted clnchanpin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACdreamoj 1011(树状数组维护字符串hash前缀和)相关的知识,希望对你有一定的参考价值。

题目链接:http://acdream.info/problem?

pid=1019

题意:两种操作,第一种将字符串某个位置的字符换为还有一个字符。另外一种查询某个连续子序列是否是回文串;

解法:有两种hash的办法,所以写了两种解法;首先hash是x1 * p^1+ x2*p^2 +x3*p^3...能够用树状数组维护前缀和,维护两个串,一个是正串。还有一个是反串用于比較。比較时候乘以对应的p倍数推断是否相等。
刘汝佳白书上的hash方法处理这道题更复杂:改动i会对后缀j产生的影响为a*p^(i-j),那么把这个式子变成a * p^i *p^(-j)  然后就是在这个位置加上a * p^i,以后查询每一个i
位置的hash值后都乘以p^i.


第一分代码:

/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef unsigned long long LL;
const int Max=1000010;
const int INF=1e9+7;
char s[Max];
LL C[2][Max];
LL Hash[Max];
int seed=13;
void init()
{
    Hash[0]=1;
    for(int i=1; i<Max; i++)
        Hash[i]=Hash[i-1]*seed;
}
int len;
void update(int i,int pos,LL data)
{
    while(pos<=len)
    {
        C[i][pos]+=data;
        pos+=pos&(-pos);
    }
}
LL get(int i,int pos)
{
    LL ans=0;
    while(pos)
    {
        ans+=C[i][pos];
        pos-=pos&(-pos);
    }
    return ans;
}
LL gethash(int i,int l,int r)
{
    return get(i,r)-get(i,l-1);
}
int main()
{
    init();
    while(scanf("%s",s+1)==1)
    {
        memset(C,0,sizeof C);
        int t;
        cin>>t;
        len=strlen(s+1);
        for(int i=1; i<=len; i++)
        {
            update(0,i,(s[i]-'a')*Hash[i]);
            update(1,len+1-i,(s[i]-'a')*Hash[len+1-i]);
        }
        while(t--)
        {
            char c;
            getchar();
            scanf("%c",&c);
            if(c=='C')
            {
                char b[5];
                int a;
                scanf("%d%s",&a,b);
                update(0,a,-(s[a]-'a')*Hash[a]);
                update(0,a,(b[0]-'a')*Hash[a]);
                update(1,len+1-a,-(s[a]-'a')*Hash[len+1-a]);
                update(1,len+1-a,(b[0]-'a')*Hash[len+1-a]);
                s[a]=b[0];
            }
            else
            {
                int l,r;
                scanf("%d%d",&l,&r);
                if(gethash(0,l,r)*Hash[len-l]==gethash(1,len+1-r,len+1-l)*Hash[r-1])
                    puts("yes");
                else
                    puts("no");
            }
        }
    }
    return 0;
}

第二份代码:

/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef  unsigned long long LL;
const int Max=1000010;
const LL INF=1000000007;
char s[Max];
char s2[Max];
LL Hash[Max];
LL C[Max];
LL C2[Max];
int seed=13;
int len;
void init()
{
    Hash[0]=1;
    for(int i=1; i<Max; i++)
        Hash[i]=(Hash[i-1]*seed)%INF;
}
LL pow1(LL a,LL k)
{
    LL ans=1;
    while(k)
    {
        if(k&1)
            ans=(ans*a)%INF;
        a=(a*a)%INF;
        k>>=1;
    }
    return ans;
}
void update(int pos,LL value)
{
    while(pos!=0)
    {
        C[pos]=(C[pos]+value+INF)%INF;
        pos-=pos&(-pos);
    }
}
void update2(int pos,LL value)
{
    while(pos!=0)
    {
        C2[pos]=(C2[pos]+value+INF)%INF;
        pos-=pos&(-pos);
    }
}
LL query(int pos)
{
    LL ans=0;
    while(pos<=len+1)
    {
        ans=(ans+C[pos])%INF;
        pos+=pos&(-pos);
    }
    return ans;
}
LL query2(int pos)
{
    LL ans=0;
    while(pos<=len+1)
    {
        ans=(ans+C2[pos])%INF;
        pos+=pos&(-pos);
    }
    return ans;
}
LL get(int now)
{
    LL ans=query(now);
    return (pow1(pow1(seed,now),INF-2)%INF*ans)%INF;
}
LL gethash(int l,int r)
{
    return (get(l)-get(r+1)*Hash[r+1-l]%INF+INF)%INF;
}
LL get2(int now)
{
    LL ans=query2(now);
    return (pow1(pow1(seed,now),INF-2)%INF*ans)%INF;
}
LL gethash2(int l,int r)
{
    return (get2(l)-get2(r+1)*Hash[r+1-l]%INF+INF)%INF;
}
int main()
{
    init();
    while(scanf("%s",s+1)==1)
    {
        int t;
        scanf("%d",&t);
        len=strlen(s+1);
        strcpy(s2+1,s+1);
        reverse(s2+1,s2+len+1);
        memset(C,0,sizeof C);
        memset(C2,0,sizeof C2);
        for(int i=1; i<=len; i++)
        {
            update(i,(s[i]-'a')*Hash[i]%INF);//a*x^(i-j)=a*x^i*(x^-j);
            update2(i,(s2[i]-'a')*Hash[len+1-i]%INF);
        }
        while(t--)
        {
            char c[5];
            scanf("%s",c);
            //printf(c);
            if(c[0]=='C')
            {
                int a;
                char b[5];
                scanf("%d%s",&a,b);
                update(a,('a'-s[a])*Hash[a]%INF);
                update(a,(b[0]-'a')*Hash[a]%INF);
                update2(len+1-a,('a'-s2[len+1-a])*Hash[len+1-a]%INF);
                update2(len+1-a,(b[0]-'a')*Hash[len+1-a]%INF);
                s[a]=b[0];
                s2[len+1-a]=b[0];
            }
            else
            {
                int l;
                int r;
                scanf("%d%d",&l,&r);
                if(r-l<=1)
                {
                    puts("yes");
                    continue;
                }
                if(gethash(l,r)==gethash2(len+1-r,len+1-l))
                    puts("yes");
                else
                    puts("no");
            }
        }
    }
    return 0;
}


以上是关于ACdreamoj 1011(树状数组维护字符串hash前缀和)的主要内容,如果未能解决你的问题,请参考以下文章

树状数组模板

AcWing 楼蓝图腾(树状数组维护逆序对)

树状数组

codeforcesRound378C-dfs+树状数组

“玲珑杯”ACM比赛 Round #5 H -- Variance 简单树状数组

hdu3015树状数组 poj1990的离散化版本