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 }
View Code

 

posted @ 2018-08-30 22:22  Kaleidoscope233  阅读(154)  评论(0编辑  收藏  举报