码迷,mamicode.com
首页 > 其他好文 > 详细

HDU5785 Interesting(Manacher + 延迟标记)

时间:2016-08-03 11:51:41      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:

题目大概说给一个字符串,找到其所有子串[i...k]满足它是由两个回文串拼成的,求Σi*k。

 

官方题解这么说的:

用manacher算法O(n)求出所有的回文半径。有了回文半径后,就可以求出cntL[i]表示以i结尾的回文串的起始位置的和cntR[i]表示以i起始的回文串的结尾位置的和,然后就可以求出答案了,这里要注意奇偶长度回文串的不同处理。复杂度O(n)。

本渣渣看了好久想了好久。。才反应过来x1*y1+x1*y2+x2*y1+x2*y2=(x1+x2)*(y1+y2) 。。这个真反应不过来= =太渣了。。那么只要求出cntL[i]和cntR[i],Σ(cntL[i]*cntR[i+1])就是要的答案了。

本渣渣又看了好久想了好久。。才想到怎么在O(n)求出cntL[i]和cntR[i]。。

 

  • 首先,跑一下Manacher就能知道每个位置向左和向右最多能延伸的长度

比如中间位置是i(回文串是奇数的情况,偶数同理。另外先不管跑Manacher前插入的特殊字符,因为也同理。。),p[i]表示Manacher求得的延伸半径。

  1. 那么[i-p[i]+1, i+p[i]-1]就是回文串,故cntL[i+p[i]-1]就该加上i-p[i]+1;
  2. 而[i-p[i]+2, i+p[i]-2]也是回文串,cntL[i+p[i]-2]就该加上i-p[i]+2…………

总之可以知道这个就相当于,对于cntL数组要在[i, i+p[i]-1]区间上依次加上一个末项为i-p[i]+1且公差为-1的等差数列,cntR也是同理的这儿同样就不说了。

  • 那么现在问题就是怎么对区间更新,让区间[L,R]加上一个首项k公差-1的等差数列,这些更新操作完成后要进行单点的查询,而且整个的时间复杂度要为O(n)。

区间更新自然就联想到延迟标记。即,更新操作就用O(1)打打标记,所有更新操作完成后,从左往右O(n)遍历过去,把标记传递过去,并更新真实的值。

  • 那么打什么标记?

首先能想到有一个加标记sumtag,表示这个数需要加多少。对于让区间[L,R]加上一个首项k公差-1的等差数列,就让sumtag[L]+=k,然后传递标记中访问到L时把sumtag[L]加到真实的值里,并把标记下传,即sumtag[L+1]+=sumtag[L]-1。不过考虑到多个区间修改有叠加,那么应该还要开几个数组记录各个点有多少个更新操作,sumcnt,那么下传也就要改成sumtan[L+1]+=sumtag[L]-sumcnt[L],另外sumcnt也要传递下去,即sumcnt[L+1]+=sum[cnt]。

不过这样还不够,因为这么传递会一直传递到数组尾巴,也就是说相当于更新了[L,MAXN]区间,而我们要的是[L,R]区间的更新,多更新了[R+1,MAXN]这个区间,而这个区间显然也是加上了一个等差数列!所以,考虑再用一个标记,减标记subtag,表示区间需要减的数,对于多更新的只要在subtag[R+1]这儿打上个标记就OK了!这个与sumtag是一样的,最后遍历标记下传的同时减去subtag的值即可,当然也需要subcnt。

于是这题就能这么解决了。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define MAXN 1111111
 6 
 7 char s[MAXN<<1];
 8 int p[MAXN<<1];
 9 void manacher(){
10     int mx=0,id;
11     for(int i=1;s[i];++i){
12         if(mx>i) p[i]=min(p[2*id-i],mx-i);
13         else p[i]=1;
14         for(;s[i+p[i]]==s[i-p[i]];++p[i]);
15         if(p[i]+i>mx){
16             mx=p[i]+i;
17             id=i;
18         }
19     }
20 }
21 
22 char str[MAXN];
23 
24 long long val[2][MAXN];
25 long long addtag[2][MAXN],addcnt[2][MAXN],subtag[2][MAXN],subcnt[2][MAXN];
26 void update(int flag,int l,int r,int k){
27     addtag[flag][l]+=k; addtag[flag][l]%=1000000007;
28     ++addcnt[flag][l];
29     subtag[flag][r+1]+=k-r+l; subtag[flag][r+1]%=1000000007;
30     ++subcnt[flag][r];
31 }
32 void pushdown(){
33     for(int i=1; str[i]; ++i){
34         if(addcnt[0][i]){
35             val[0][i]+=addtag[0][i]; val[0][i]%=1000000007;
36             addtag[0][i+1]+=addtag[0][i]-addcnt[0][i]; addtag[0][i+1]%=1000000007;
37             addcnt[0][i+1]+=addcnt[0][i];
38         }
39         if(subcnt[0][i]){
40             val[0][i]-=subtag[0][i]; val[0][i]%=1000000007;
41             subtag[0][i+1]+=subtag[0][i]-subcnt[0][i]; subtag[0][i+1]%=1000000007;
42             subcnt[0][i+1]+=subcnt[0][i];
43         }
44         if(addcnt[1][i]){
45             val[1][i]+=addtag[1][i]; val[1][i]%=1000000007;
46             addtag[1][i+1]+=addtag[1][i]-addcnt[1][i]; addtag[1][i+1]%=1000000007;
47             addcnt[1][i+1]+=addcnt[1][i];
48         }
49         if(subcnt[1][i]){
50             val[1][i]-=subtag[1][i]; val[1][i]%=1000000007;
51             subtag[1][i+1]+=subtag[1][i]-subcnt[1][i]; subtag[1][i+1]%=1000000007;
52             subcnt[1][i+1]+=subcnt[1][i];
53         }
54     }
55 }
56 
57 int main(){
58     while(~scanf("%s",str+1)){
59         s[0]=$;
60         int i=1;
61         for(;str[i];++i){
62             s[(i<<1)-1]=#;
63             s[i<<1]=str[i];
64         }
65         s[(i<<1)-1]=#;
66         s[i<<1]=0;
67         manacher();
68 
69         memset(val,0,sizeof(val));
70         memset(addtag,0,sizeof(addtag));
71         memset(addcnt,0,sizeof(addcnt));
72         memset(subtag,0,sizeof(subtag));
73         memset(subcnt,0,sizeof(subcnt));
74 
75         for(int i=1; s[i]; ++i){
76             if(i&1){
77                 if(p[i]/2==0) continue;
78                 update(0,i/2-p[i]/2+1,i/2,i/2+p[i]/2);
79                 update(1,i/2+1,i/2+p[i]/2,i/2);
80             }else{
81                 update(0,i/2-p[i]/2+1,i/2,i/2+p[i]/2-1);
82                 update(1,i/2,i/2+p[i]/2-1,i/2);
83             }
84         }
85         pushdown();
86 
87         long long ans=0;
88         for(int i=1; str[i]&&str[i+1]; ++i){
89             ans+=val[1][i]*val[0][i+1];
90             ans%=1000000007;
91         }
92         if(ans<0) ans+=1000000007;
93         printf("%I64d\n",ans);
94     }
95     return 0;
96 }

 

HDU5785 Interesting(Manacher + 延迟标记)

标签:

原文地址:http://www.cnblogs.com/WABoss/p/5732205.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!