ccpc哈尔滨A [HDU-6230] Palindrome Manacher+树状数组

提交链接

Alice like strings, especially long strings. For each string, she has a special evaluation system to judge how elegant the string is. She defines that a string S1..3n−2S1..3n−2 is one-and-half palindromic if and only if it satisfies S[i]=S[2n−i]=S2n+i−2S[i]=S[2n−i]=S2n+i−2.For example, abcbabcabcbabc is one-and-half palindromic string, and abccbaabcabccbaabc is not. Now, Alice has generated some long strings. She ask for your help to find how many substrings which is one-and-half palindromic.

Input
The first line is the number of test cases. For each test case, there is only one line containing a string(the length of strings is less than or equal to 500000500000), this string only consists of lowercase letters.

Output
For each test case, output a integer donating the number of one-and-half palindromic substrings.

Sample Input
1
ababcbabccbaabc

Sample Output
2

Hint
In the example input, there are two substrings which are one-and-half palindromic strings, <nobr> abab </nobr> and <nobr> abcbabc </nobr>.

题意:给定一个字符串,统计有多少个子串是one−and−half palindromic. (即字符串长度为3n−2,且满足S[i]=S[2n−i]=S[2n+i]
题意:问题目描述的字串有多少个?

思路:
+ 可以发现这种字符串是关于S[n]和S[2n-1]对称的,所以枚举S[2n-1],看在S[2n-1]的半径范围内有多少个S[n]的半径范围包括S[2n-1],可以manacher找到半径,然后树状数组求答案;
+
对one−and−half palindromic字符串稍作分析:可以发现,
这种字符串的形式是这样的:$L(S)@R(S)$L(S)@ $、@
分别表示某一个小写字母。 L(S)、R(S)分别表示某一个字符串,和该字符串的逆串(可为空串)。
首先,用Manacher预处理出每个字符为中心的最长回文串长度,p[i]。 设子串中第二个@,第二个$ 在原串中的下标分别为i,j.
那么,该子串必然要满足:j−p[j]+1≤i

//此题主要是利用了树状数组或线段树来表达每个回文串中心点
//的影响,通过依次加1的方式,这样如果当前位置不是回文串
//圆心,那么他只能影响到当前位置,因为在下一个位置就被删除了
//具体可见out2,这是一个混乱串的位置
//
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6;
char Ma[maxn];
int Mp[maxn];
void Manacher(char s[],int len)
{
    int l = 0;
    Ma[l++] = '$';
    Ma[l++]='#';
    for(int i=0;i<len;i++)
    {
        Ma[l++] = s[i];
        Ma[l++] = '#';
    }
    Ma[l]=0;
   // printf("%s\n",Ma); //增加#后,字符串从1开始,不带开头的$号,字符串长度为奇数
  int mx = 0,id = 0;
   for(int i=0;i<l;i++)
   {
       Mp[i] = mx>i?min(Mp[2*id-i],mx-i):1;
       while(Ma[i+Mp[i]]==Ma[i-Mp[i]])
        Mp[i]++;
        if(i+Mp[i]>mx)
       {
           mx = i+Mp[i];
           id = i;
       }
   }
}
vector<int>v[maxn];
char s[maxn];
int c[maxn];
int len;
int lowbit(int x)
{
    return x&-x;
}
void add(int pos,int val)
{
    pos++;
    for(int i=pos;i<=len;i+=lowbit(i))
        c[i]+=val;
}
int getsum(int pos)
{
    pos++;
    int ret = 0;
    for(int i=pos;i>0;i-=lowbit(i))
    {
        ret+=c[i];
    }
    return ret;
}
int main()
{
    //freopen("out.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",s);
        len = strlen(s);
        Manacher(s,len);
// for(int i=0;i<len;i++)
// {
// printf("%d ",Mp[i]);
// }
// cout<<endl;
// 这是增加了#后得到的答案数组
        for(int i=0;i<len;i++)
        {
            Mp[i] = Mp[i*2+2]/2;
        }
// 这步是去掉#后得到的原字符串的答案数组
// for(int i=0;i<len;i++)
// {
// printf("%d ",Mp[i]);
// }
// cout<<endl; //打印出来看
        for(int i=0;i<len;i++)
           v[i].clear();
           for(int i=0;i<len;i++)
            c[i] = 0;
           long long ans = 0;
           for(int i=0;i<len;i++)
           {
               for(int pos:v[i])
                add(pos,-1);//这一步是用来消除影响的
               int st = i-Mp[i]+1;//计算字符的影响范围的左端点,避免重复计算
// cout<<"i:"<<i<<" st:"<<st<<endl;
// cout<<getsum(i-1)<<" "<<getsum(st-1)<<endl;
               ans+=getsum(i-1)-getsum(st-1);
               //注意前缀和的用法,左区间端点减1
               //这里虽然是i位置加的ans,但是表示的确是ans-1出存在一个串心(类比圆心)
               add(i,1);//这个是基础,用来表示每个位置的影响
// cout<<i+Mp[i]<<endl;
// cout<<endl;
               v[i+Mp[i]].push_back(i);//通过这一步,延迟那些有回文串的
               //串心的影响范围

// for(int i=0;i<len;i++)
// printf("%d ",getsum(i)); //打印前缀和
// cout<<endl;
           }
// for(int i=0;i<len;i++)
// {
// int uu = v[i].size();
// cout<<"i"<<i<<" ";
// for(int j=0;j<uu;j++)
// {
// printf("%d ",v[i][j]);
// }
// cout<<endl;
// }
           printf("%lld\n",ans);
    }
    return 0;
}

下面是两组测试数据

out1

$#a#b#a#b#c#b#a#b#c#c#b#a#a#b#c#
1 1 2 1 4 1 4 1 2 1 8 1 2 1 6 
1 2 2 1 4 1 3 1 1 1 1 1 1 1 1 
i:0 st:0
0 0
1

1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  
i:1 st:0
0 0
3

0  1  1  1  1  1  1  1  1  1  1  1  1  1  1  
i:2 st:1
1 0
4

0  1  2  2  2  2  2  2  2  2  2  2  2  2  2  
i:3 st:3
1 1
4

0  0  1  2  2  2  2  2  2  2  2  2  2  2  2  
i:4 st:1
0 0
8

0  0  0  0  1  1  1  1  1  1  1  1  1  1  1  
i:5 st:5
1 1
6

0  0  0  0  1  2  2  2  2  2  2  2  2  2  2  
i:6 st:4
1 0
9

0  0  0  0  1  1  2  2  2  2  2  2  2  2  2  
i:7 st:7
2 2
8

0  0  0  0  1  1  2  3  3  3  3  3  3  3  3  
i:8 st:8
1 1
9

0  0  0  0  0  0  1  1  2  2  2  2  2  2  2  
i:9 st:9
0 0
10

0  0  0  0  0  0  0  0  0  1  1  1  1  1  1  
i:10 st:10
0 0
11

0  0  0  0  0  0  0  0  0  0  1  1  1  1  1  
i:11 st:11
0 0
12

0  0  0  0  0  0  0  0  0  0  0  1  1  1  1  
i:12 st:12
0 0
13

0  0  0  0  0  0  0  0  0  0  0  0  1  1  1  
i:13 st:13
0 0
14

0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  
i:14 st:14
0 0
15

0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  
i0 
i1 0 
i2 
i3 1 
i4 2 3 
i5 
i6 5 
i7 
i8 4 7 
i9 6 8 
i10 9 
i11 10 
i12 11 
i13 12 
i14 13 
2

out2

$#a#s#d#u#i#o#q#w#s#h#p#q#o#i#k#
1 1 2 1 2 1 2 1 2 1 2 1 2 1 2 
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
i:0 st:0
0 0
1

1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  
i:1 st:1
0 0
2

0  1  1  1  1  1  1  1  1  1  1  1  1  1  1  
i:2 st:2
0 0
3

0  0  1  1  1  1  1  1  1  1  1  1  1  1  1  
i:3 st:3
0 0
4

0  0  0  1  1  1  1  1  1  1  1  1  1  1  1  
i:4 st:4
0 0
5

0  0  0  0  1  1  1  1  1  1  1  1  1  1  1  
i:5 st:5
0 0
6

0  0  0  0  0  1  1  1  1  1  1  1  1  1  1  
i:6 st:6
0 0
7

0  0  0  0  0  0  1  1  1  1  1  1  1  1  1  
i:7 st:7
0 0
8

0  0  0  0  0  0  0  1  1  1  1  1  1  1  1  
i:8 st:8
0 0
9

0  0  0  0  0  0  0  0  1  1  1  1  1  1  1  
i:9 st:9
0 0
10

0  0  0  0  0  0  0  0  0  1  1  1  1  1  1  
i:10 st:10
0 0
11

0  0  0  0  0  0  0  0  0  0  1  1  1  1  1  
i:11 st:11
0 0
12

0  0  0  0  0  0  0  0  0  0  0  1  1  1  1  
i:12 st:12
0 0
13

0  0  0  0  0  0  0  0  0  0  0  0  1  1  1  
i:13 st:13
0 0
14

0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  
i:14 st:14
0 0
15

0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  
i0 
i1 0 
i2 1 
i3 2 
i4 3 
i5 4 
i6 5 
i7 6 
i8 7 
i9 8 
i10 9 
i11 10 
i12 11 
i13 12 
i14 13 
0
全部评论

相关推荐

脾气小祖宗:这简历摸到都得狠狠地消毒液洗手😂
点赞 评论 收藏
分享
头像
10-13 18:10
已编辑
东南大学 C++
。收拾收拾心情下一家吧————————————————10.12更新上面不知道怎么的,每次在手机上编辑都会只有最后一行才会显示。原本不想写凉经的,太伤感情了,但过了一天想了想,凉经的拿起来好好整理,就像象棋一样,你进步最快的时候不是你赢棋的时候,而是在输棋的时候。那废话不多说,就做个复盘吧。一面:1,经典自我介绍2,项目盘问,没啥好说的,感觉问的不是很多3,八股问的比较奇怪,他会深挖性地问一些,比如,我知道MMU,那你知不知道QMMU(记得是这个,总之就是MMU前面加一个字母)4,知不知道slab内存分配器-&gt;这个我清楚5,知不知道排序算法,排序算法一般怎么用6,写一道力扣的,最长回文子串反问:1,工作内容2,工作强度3,关于友商的问题-&gt;后面这个问题问HR去了,和中兴有关,数通这个行业和友商相关的不要提,这个行业和别的行业不同,别的行业干同一行的都是竞争关系,数通这个行业的不同企业的关系比较微妙。特别细节的问题我确实不知道,但一面没挂我。接下来是我被挂的二面,先说说我挂在哪里,技术性问题我应该没啥问题,主要是一些解决问题思路上的回答,一方面是这方面我准备的不多,另一方面是这个面试写的是“专业面试二面”,但是感觉问的问题都是一些主管面/综合面才会问的问题,就是不问技术问方法论。我以前形成的思维定式就是专业面会就是会,不会就直说不会,但事实上如果问到方法论性质的问题的话得扯一下皮,不能按照上面这个模式。刚到位置上就看到面试官叹了一口气,有一些不详的预感。我是下午1点45左右面的。1,经典自我介绍2,你是怎么完成这个项目的,分成几个步骤。我大致说了一下。你有没有觉得你的步骤里面缺了一些什么,(这里已经在引导我往他想的那个方向走了),比如你一个人的能力永远是不够的,,,我们平时会有一些组内的会议来沟通我们的所思所想。。。。3,你在项目中遇到的最困难的地方在什么方面4,说一下你知道的TCP/IP协议网络模型中的网络层有关的协议......5,接着4问,你觉得现在的socket有什么样的缺点,有什么样的优化方向?6,中间手撕了一道很简单的快慢指针的问题。大概是在链表的倒数第N个位置插入一个节点。————————————————————————————————————10.13晚更新补充一下一面说的一些奇怪的概念:1,提到了RPC2,提到了fu(第四声)拷贝,我当时说我只知道零拷贝,知道mmap,然后他说mmap是其中的一种方式,然后他问我知不知道DPDK,我说不知道,他说这个是一个高性能的拷贝方式3,MMU这个前面加了一个什么字母我这里没记,别问我了4,后面还提到了LTU,VFIO,孩子真的不会。
走呀走:华子二面可能会有场景题的,是有些开放性的问题了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务