Gym - 100570E:Palindrome Query (hash+BIT+二分维护回文串长度)
题意:给定字符串char[],以及Q个操作,操作有三种:
1:pos,chr:把pos位置的字符改为chr
2:pos:问以pos为中心的回文串长度为多长。
3:pos:问以pos,pos+1为中心的回文串长度为多长。
思路:用hash表示一段字符串或者连续子串。我们用BIT记录hash前缀和,那么也可以用BIT修改前缀和。然后blabla,乱搞就行了。
当然为了保险,最好用双hash。
(此题暴力也可以过!
暴力代码:3962ms
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=100010; char c[maxn],t; int main() { int N,Q,opt,x; scanf("%s%d",c+1,&Q); N=strlen(c+1); while(Q--){ scanf("%d%d",&opt,&x); if(opt==1){ scanf(" %c",&t); c[x]=t; } else if(opt==2){ int i=x,j=x; while(i-1>=1&&j+1<=N&&c[i-1]==c[j+1]) i--,j++; printf("%d\n",j-i+1); } else { if(c[x]!=c[x+1]) { puts("-1"); continue;} int i=x,j=x+1; while(i-1>=1&&j+1<=N&&c[i-1]==c[j+1]) i--,j++; printf("%d\n",j-i+1); } } return 0; }
hash+BIT+二分:93ms(目前排第一?
#include<bits/stdc++.h> #define uint unsigned int using namespace std; const int maxn=100010; const uint seed=131; char c[maxn]; uint sum[maxn][2],p[maxn]; int N; uint query(int x,int opt){ uint res=0; while(x) { res+=sum[x][opt]; x-=(-x)&x; } return res; } bool check(int L,int R) { if(L<1||R>N) return false; uint h1=(query(R,0)-query(L-1,0))*p[L-1]; uint h2=(query(R,1)-query(L-1,1))*p[N-R]; if(h1==h2) return true; return false; } int main() { int Q,i,j; scanf("%s%d",c+1,&Q); N=strlen(c+1); p[0]=1; for(i=1;i<=N;i++) p[i]=p[i-1]*seed; for(i=1;i<=N;i++){ for(j=i;j<=N;j+=(-j)&j) sum[j][0]+=p[N-i]*c[i]; for(j=i;j<=N;j+=(-j)&j) sum[j][1]+=p[i-1]*c[i]; } int opt,x,L,R,Mid,ans; char chr; while(Q--){ scanf("%d%d",&opt,&x); if(opt==1){ scanf(" %c",&chr); for(j=x;j<=N;j+=(-j)&j) sum[j][0]+=p[N-x]*(chr-c[x]); for(j=x;j<=N;j+=(-j)&j) sum[j][1]+=p[x-1]*(chr-c[x]); c[x]=chr; } else if(opt==2){ L=0; R=N; ans=1; while(L<=R){ Mid=(L+R)>>1; if(check(x-Mid,x+Mid)) ans=Mid,L=Mid+1; else R=Mid-1; } printf("%d\n",ans*2+1); } else{ L=0; R=N; ans=-1; while(L<=R){ Mid=(L+R)>>1; if(check(x-Mid,x+1+Mid)) ans=Mid,L=Mid+1; else R=Mid-1; } printf("%d\n",ans==-1?-1:ans*2+2); } } return 0; }
It is your time to fight!