BZOJ 2084: [Poi2010]Antisymmetry(Hash+二分)
求一个01序列的子串取反并反转后与原串相同的个数.
很显而易见的是,反转的话只要子串对应的i和n-i+1位相反即可,这个看一下样例能很快看出来.
所以我们正着求一遍hash,反着取反然后求hash.
枚举中间点,二分一下这个子串长度的一半,check的话就是判断前一半子串的正hash值与后一半子串取反后的反hash值是否相等.
答案怎么统计呢,显然,如果一个子串满足条件,那么去掉首位得到的子串也满足条件,ans+=len/2...
然而细节写错wa了2发。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #include <queue> 7 #include <map> 8 #define ll long long 9 #define out(a) printf("%lld ",a) 10 #define writeln printf("\n") 11 const int N=5e5+50; 12 const int MOD=1e9+7; 13 const int base=233; 14 using namespace std; 15 int n; 16 char s[N]; 17 ll Hash1[N],Hash2[N],Pow[N]; 18 ll ans; 19 int read() 20 { 21 int s=0,t=1; char c; 22 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 23 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 24 return s*t; 25 } 26 ll readl() 27 { 28 ll s=0,t=1; char c; 29 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 30 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 31 return s*t; 32 } 33 ll get(int l,int r,int x) 34 { 35 if (x==1) return (Hash1[r]-(ll)Hash1[l-1]*Pow[r-l+1]%MOD+MOD)%MOD; 36 return (Hash2[l]-(ll)Hash2[r+1]*Pow[r-l+1]%MOD+MOD)%MOD; 37 } 38 int solve(int x) 39 { 40 int l=1,r=min(x,n-x),mid=0; bool flag=false; 41 while (l<=r){ 42 mid=(l+r)>>1; 43 if (get(x-mid,x+mid-1,1)==get(x-mid,x+mid-1,2)) flag=true,l=mid+1; 44 else r=mid-1; 45 } 46 //out(x),out(r),writeln; 47 if (flag) return r; 48 return 0; 49 } 50 int main() 51 { 52 n=read(); Pow[0]=1; 53 scanf("%s",s); 54 for (int i=1;i<=n;i++) 55 Pow[i]=Pow[i-1]*base%MOD; 56 for (int i=0;i<n;i++) 57 Hash1[i]=(Hash1[i-1]*base+s[i])%MOD; 58 for (int i=n-1;i>=0;i--) 59 Hash2[i]=(Hash2[i+1]*base+(48+49-s[i]))%MOD; 60 for (int i=1;i<n;i++) 61 ans+=solve(i); 62 out(ans); 63 return 0; 64 }