bzoj 3676 回文串 manachar+hash

       考虑每个回文串,它一定是它中心字母的最长回文串两侧去掉同样数量的字符后的一个子串。

       所以我们可以用manachar求出每一位的回文半径,放到哈希表里并标记出它的下一个子串。

       最后拓扑排序递推就行了。。。

       这道题丧心病狂卡哈希。。。。wa了一屏。。。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<map>
  7 #define bas 131
  8 #define bs 31
  9 #define p 1000000007
 10 #define p2 986598521
 11 #define ll long long
 12 #define N 1200005
 13 using namespace std;
 14 char c[N],s[N*3];
 15 int hui[N],n;
 16 ll hash[N],pw[N],hash2[N],pw2[N];
 17 int head[1000005],nxt[N],tot,len[N],size[N],zhi[N];
 18 ll key[N],key2[N],nx[N],nx2[N];
 19 void insert(ll x,ll xx,int l,ll z,int ss,ll ww)
 20 {
 21     int y=x%1000003;
 22     tot++;nxt[tot]=head[y];head[y]=++tot;len[tot]=l;key[tot]=x;nx[tot]=z;zhi[tot]=ss;key2[tot]=xx;nx2[tot]=ww;
 23     return ;
 24 }
 25 int find(ll x,ll xx)
 26 {
 27     int y=x%1000003;
 28     for(int i=head[y];i;i=nxt[i])
 29     {
 30         if(key[i]==x&&key2[i]==xx)return i;
 31     }
 32     return 0;
 33 }
 34 int head2[N],ver2[N],nxt2[N],tot2;
 35 void add2(int x,int y)
 36 {
 37     tot2++;nxt2[tot2]=head2[x];head2[x]=tot2;ver2[tot2]=y;return ;
 38 }
 39 void manachar()
 40 {
 41     int mx=0,id=0;
 42     for(int i=1;i<=n;i++)
 43     {
 44         if(i>mx)
 45         {
 46             hui[i]=1;
 47             mx=i;id=i;
 48         }
 49         else
 50         {
 51             hui[i]=min(hui[id-(i-id)],mx-i+1);
 52         }
 53         int l=i-hui[i],r=i+hui[i];
 54         while(l!=0&&r!=n+1&&s[l]==s[r])
 55         {
 56              hui[i]++;
 57              mx=i+hui[i]-1;
 58              id=i;
 59              l--;r++;
 60         }
 61         int tmp=hui[i];
 62         if(s[i+hui[i]-1]=='#')tmp--;
 63         if(tmp==0)continue;
 64         int pos2=tmp+i-1,pos1=i-tmp+1;
 65         int lenn=(pos2-pos1)/2+1;
 66         ll haha,haha2;
 67         ll ha=(hash[pos2/2]-(hash[pos1/2-1]*pw[lenn])%p+p)%p;
 68         ll ha2=(hash2[pos2/2]-(hash2[pos1/2-1]*pw2[lenn])%p2+p2)%p2;
 69         if(pos2==pos1||pos2==pos1+2)haha=0,haha2=0;
 70         else haha=(hash[pos2/2-1]-(hash[pos1/2]*pw[lenn-2])%p+p)%p,haha2=(hash2[pos2/2-1]-(hash2[pos1/2]*pw2[lenn-2])%p2+p2)%p2;
 71         int k=find(ha,ha2);
 72         if(!k)insert(ha,ha2,lenn,haha,pos2/2,haha2),size[tot]++;
 73         else size[k]++;
 74     }
 75 }
 76 queue<int>qu;
 77 int ru[N];
 78 ll ans;
 79 void tupu()
 80 {
 81        for(int i=1;i<=tot;i++)if(!ru[i])qu.push(i);
 82     while(!qu.empty())
 83     {
 84         int tmp=qu.front();qu.pop();
 85         ans=max(ans,(ll)size[tmp]*len[tmp]);
 86         for(int i=head2[tmp];i;i=nxt2[i])
 87         {
 88             ru[ver2[i]]--;
 89             size[ver2[i]]+=size[tmp];
 90             if(!ru[ver2[i]])qu.push(ver2[i]);
 91         }
 92     }
 93 }
 94 int main()
 95 {
 96     scanf("%s",c+1);
 97     n=strlen(c+1);
 98     pw[0]=1;pw2[0]=1;
 99     for(int i=1;i<=n;i++)pw[i]=(pw[i-1]*bas)%p;
100     for(int i=1;i<=n;i++)pw2[i]=(pw2[i-1]*bs)%p2;
101     for(int i=1;i<=n;i++)hash[i]=(hash[i-1]*bas+c[i]-'a'+1)%p;
102     for(int i=1;i<=n;i++)hash2[i]=(hash2[i-1]*bs+c[i]-'a'+1)%p2;
103     for(int i=1;i<=n*2+1;i++)
104     {
105         if(i&1)s[i]='#';
106         else s[i]=c[i/2];
107     }
108     n=n*2+1;
109     manachar();
110     for(int i=1;i<=tot;i++)
111     {
112         if(nx[i]==0)continue;
113         int tmp=find(nx[i],nx2[i]);
114         if(tmp!=0)add2(i,tmp),ru[tmp]++;
115         else
116         {
117             ll now,now2;
118             if(len[i]<=4)now=0,now2=0;
119             else 
120             {
121                 now=(hash[zhi[i]-2]-(hash[zhi[i]-len[i]+2]*pw[len[i]-4])%p+p)%p;
122                 now2=(hash2[zhi[i]-2]-(hash2[zhi[i]-len[i]+2]*pw2[len[i]-4])%p2+p2)%p2;
123             }
124             insert(nx[i],nx2[i],len[i]-2,now,zhi[i]-1,now2);
125             add2(i,tot);ru[tot]++;
126         }
127     }
128     tupu();
129     printf("%lld\n",ans);
130     return 0;
131 }

 

 
posted @ 2016-12-28 14:36  SD_le  阅读(288)  评论(0编辑  收藏  举报
重置按钮