这道题也算是卡了很久了 - -
最近才发现有些细节没考虑到。
思路是用两颗树状数组维护HASH前缀和 (一正一反两个反向)
坑1:线段树不是MLE就是TLE
坑2:在查出两个串后 多项式的幂是不一样的(s[3] * 1331 ^ 3 + s[4] * 1331 ^ 4 + s[5] * 1331 ^ 5 和 s[3] * 1331 ^ 2+s[4] * 1331 ^ 1 + s[5] * 1331 ^ 0),
不能用除法统一幂。因为这种HASH的原理是unsiged long long 溢出 相当于取余了。
这里就要用逆元 然而我并不会。所以我们把幂小的乘以一个数让他的幂变大 - -
/*
* this code is made by Hivoodoo
* Problem: 1019
* Verdict: Accepted
* Submission Date: 2015-10-03 13:03:06
* Time: 1336MS
* Memory: 41716KB
*/
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int MAXN = 1e6+10;
ULL xl[MAXN];
//适用于正整数
template <class T>
inline void scan_d(T &ret)
{
char c;
ret=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
int n;
struct BIT
{
inline int lowbit(int x)
{
return x&-x;
}
ULL a[MAXN],b[MAXN];
void init()
{
for(int i=0; i<=n; i++)
a[i]=b[i]=0;
}
void add(int pos, ULL v)
{
for(int i=pos; i<=n; i+=lowbit(i))
a[i] += v;
}
ULL sum(int pos)
{
ULL ret = 0;
for (int i=pos; i>0; i-=lowbit(i))
ret += a[i];
return ret;
}
void update(int pos,ULL v)
{
pos++;
if(b[pos])
add(pos,-b[pos]);
add(pos,b[pos]=v);
}
ULL query(int a,int b)
{
a,b++;
return sum(b)-sum(a);
}
} soul[2];
char s[MAXN];
int main()
{
int m;
xl[0]=1;
for(int i=1; i<MAXN-1; i++)
xl[i]=xl[i-1]*13331;
while(scanf("%s",s)!=EOF)
{
n=strlen(s);
soul[0].init();
soul[1].init();
scan_d(m);
for(int i=0,j=n-1; i<n; i++,j--)
soul[0].update(i,xl[i]*s[i]),soul[1].update(j,xl[j]*s[i]);
while(m--)
{
int a,b;
scanf("%s",s);
if(s[0]=='Q')
{
scan_d(a);
scan_d(b);
if(a>b)
swap(a,b);
a--,b--;
ULL ra=soul[0].query(a,b);
ULL rb=soul[1].query(n-b-1,n-a-1);
int d=n-b-1-a;
if(d>0)
ra*=xl[d];
else
rb*=xl[-d];
if(ra==rb)
puts("yes");
else
puts("no");
}
else
{
scan_d(a);
scanf("%s",s);
a--;
soul[0].update(a,s[0]*xl[a]);
soul[1].update(n-a-1,s[0]*xl[n-a-1]);
}
}
}
return 0;
}

本文详细解析了ACDream 1019 Palindrome问题的解决思路,利用两棵树状数组来维护HASH前缀和,通过正反两个方向处理字符串,并针对多项式幂的不同进行了特殊处理,最终实现高效判断回文子串。

被折叠的 条评论
为什么被折叠?



