多校#5-1005-Instring-HDU5785-manacher+维护

寻找三元组(i,j,k),使得(i,j)(j,k)都是回文字串,其中i<=j<k.

可以发现,对于每一位i,只要预处理出来有多少个以i为右端的回文串和以i为左端的回文串。把那些串的另一端的坐标和计算出来就可以了。

然后ans = ∑cntR[i]*cntL[i+1]

这里cntR[i]记录以i为右端的回文串的左端坐标和。cntL[i]同理。

然后这道题的数据范围是1e6,多case。必须要O(n)才能过。

首先用O(n)的Manacher处理每一位的回文半径,之后遍历处理

可以发现这里需要O(n)复杂度给指定区间加上一个等差序列。于是开几个数组维护,空间换时间。

用cnt_add记录加了多少次,add记录首项加了多少,这样从首项往后递推,每次add[i+1] = add[i]-cnt_add[i] cnt_add[i+1] += cnt_add[i] cntL[i] += add[i]

这样可以从首项更新到字符串尾。但是我们要更新一段值,就有一段多加了,于是就再开一个mns记录多加的的值.

比如要更新[l,r] 那么就给mns[r+1]置为add[r+1]时的值。这样就可以把多加的抵消了。同时也要维护一个cnt_mns记录次数。

最后还要注意分回文长度奇偶讨论。

//坑了好久的题。最开始想到了用树状数组维护cnt,成段更新,然而卡log。

  1 #include <cstdio>
  2 #include <ctype.h>
  3 #include <cstring>
  4 #include <algorithm>
  5 
  6 #define LL long long
  7 #define lson rt<<1,l,mid
  8 #define rson rt<<1|1,mid+1,r
  9 #define root 1,N,1
 10 using namespace std;
 11 
 12 const int maxn = 1e6+100;
 13 const LL MOD = 1e9+7;
 14 
 15 char Ma[2*maxn];
 16 int Mp[2*maxn];
 17 void update(LL &x,LL d)
 18 {
 19     x += d;
 20     if(x >= MOD) x -= MOD;
 21     if(x < 0) x += MOD;
 22 }
 23 
 24 void Manacher(char s[],int len)
 25 {
 26     memset(Mp,0,sizeof Mp);
 27     int l = 0;
 28     Ma[l++] = '$';
 29     Ma[l++] = '#';
 30     for(int i=0;i<len;i++)
 31     {
 32         Ma[l++] = s[i];
 33         Ma[l++] = '#';
 34     }
 35     Ma[l] = 0;
 36     int mx = 0,id = 0;
 37     for(int i=0;i<l;i++)
 38     {
 39         Mp[i] = mx > i ? min(Mp[2*id-i],mx-i) : 1;
 40         while(Ma[i+Mp[i]] == Ma[i-Mp[i]] ) Mp[i]++;
 41         if(i + Mp[i] > mx)
 42         {
 43             mx = i+Mp[i];
 44             id = i;
 45         }
 46     }
 47 }
 48 
 49 char line[maxn];
 50 int p[maxn];
 51 LL cntL[maxn],cntR[maxn];
 52 LL add[maxn],mns[maxn];
 53 LL cnt_add[maxn],cnt_mns[maxn];
 54 
 55 void init()
 56 {
 57     memset(cnt_mns,0,sizeof cnt_mns);
 58     memset(cnt_add,0,sizeof cnt_add);
 59     memset(add,0,sizeof add);
 60     memset(mns,0,sizeof mns);
 61 }
 62 
 63 LL ans = 0;
 64 void solve(int len)
 65 {
 66     init();
 67     for(int i=2;i<2*len+1;i++)
 68     {
 69         int tmp = Mp[i];
 70         if(Ma[i] == '#')
 71         {
 72             int cur = i/2+1,L = (i-tmp)/2+1, R = (i+tmp)/2-1,r = (tmp-1)/2;
 73             update(add[L],R);
 74             update(mns[cur],R-r);
 75             cnt_add[L] ++;
 76             cnt_mns[cur]++;
 77         }else
 78         {
 79             int cur = i/2,L = (i-tmp)/2+1, R = (i+tmp)/2-1,r = 1+(tmp-1)/2;
 80             update(add[L],R);
 81             update(mns[cur+1],R-r);
 82             cnt_add[L] ++;
 83             cnt_mns[cur+1]++;
 84         }
 85     }
 86     for(int i=1;i<=len;i++)
 87     {
 88         update(cntL[i],add[i]-mns[i]);
 89         update(add[i+1],add[i]-cnt_add[i]);
 90         update(mns[i+1],mns[i]-cnt_mns[i]);
 91         update(cnt_add[i+1],cnt_add[i]);
 92         update(cnt_mns[i+1],cnt_mns[i]);
 93     }
 94 
 95     init();
 96     for(int i=2;i<2*len+1;i++)
 97     {
 98         int tmp = Mp[i];
 99         if(Ma[i] == '#')
100         {
101             int cur = i/2+1,L = (i-tmp)/2+1, R = (i+tmp)/2-1,r = (tmp-1)/2;
102             add[cur] += cur-1;
103             mns[R+1] += cur - r - 1;
104             cnt_add[cur] ++;
105             cnt_mns[R+1] ++;
106         }else
107         {
108             int cur = i/2,L = (i-tmp)/2+1, R = (i+tmp)/2-1,r = 1+(tmp-1)/2;
109             add[cur] += cur;
110             mns[R+1] += cur-r;
111             cnt_add[cur] ++;
112             cnt_mns[R+1] ++;
113         }
114     }
115     for(int i=1;i<=len;i++)
116     {
117         update(cntR[i],add[i]-mns[i]);
118         update(add[i+1],add[i]-cnt_add[i]);
119         update(mns[i+1],mns[i]-cnt_mns[i]);
120         update(cnt_add[i+1],cnt_add[i]);
121         update(cnt_mns[i+1],cnt_mns[i]);
122     }
123     ans = 0;
124     for(int i=1;i<=len;i++)
125     {
126         update(ans,(cntR[i]*cntL[i+1])%MOD);
127     }
128 }
129 
130 int main()
131 {
132     //freopen("1005.in","r",stdin);
133     while(true)
134     {
135         char c;
136         int len = 0;
137         while((c = getchar()) && isalpha(c))
138         {
139             line[len++] = c;
140         }
141         if(c == EOF) break;
142         Manacher(line,len);
143 
144         memset(cntL,0,sizeof cntL);
145         memset(cntR,0,sizeof cntR);
146         solve(len);
147         printf("%I64d\n",(ans+MOD) % MOD);
148     }
149 }

 

posted @ 2016-08-05 19:17  Helica  阅读(215)  评论(0编辑  收藏  举报