Palindrome
时间限制: 1000ms 内存限制: 128M
给出一个仅由小写字母构成的字符串,求其最长回文子串的长度。由于该字符串很长,故将其以压缩后的形式给出。压缩后的字符串有n段,其中第i段用一个整数lengthi和一个小写字母ci来描述,表示第i段是由lengthi个连续的小写字母ci组成。
输入第一行为一个整数T,表示一共有T组测试数据。
对于每组测试数据:
第一行为一个整数n(1≤n≤100000)。
接下来n行中,第i行有一个整数lengthi和一个小写字母ci以一个空格间隔(1≤lengthi≤109,ci为小写字母a−z中的一个)。
对于每组测试数据:输出一个整数表示最长回文子串长度。
复制
1 5 1 a 1 a 3 b 2 a 4 c
7
分析:可以先把连续相同字符放在一起;
然后就是求最长回文子串,枚举每一位字符,然后无脑二分哈希就好了;
代码:
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e5+10; int n,m,k,t,b[maxn],cnt,mo=12345; char op[maxn]; ll a[maxn],pre[maxn],len[maxn]; unsigned ll h1[maxn],h2[maxn],h3[maxn],h4[maxn],xp[maxn]; bool check(int len,int sta,int stb,unsigned ll *h1,unsigned ll *h2) { return h1[sta]-h1[sta+len]*xp[len]==h2[stb]-h2[stb-len]*xp[len]; } int main() { int i,j; xp[0]=1; for(i=1;i<=maxn-10;i++)xp[i]=xp[i-1]*mo; scanf("%d",&t); while(t--) { cnt=0; scanf("%d",&n); for(i=1;i<=n;i++) { int num=0; scanf("%d%s",&num,op); if(op[0]!=b[cnt]) { b[++cnt]=op[0]; a[cnt]=num; pre[cnt]=pre[cnt-1]+a[cnt]; } else a[cnt]+=num,pre[cnt]+=num; } h1[cnt+1]=h2[cnt+1]=0; for(i=cnt;i>=1;i--) { h1[i]=h1[i+1]*mo+a[i]; h2[i]=h2[i+1]*mo+b[i]-'a'; } h3[0]=h4[0]=0; for(i=1;i<=cnt;i++) { h3[i]=h3[i-1]*mo+a[i]; h4[i]=h4[i-1]*mo+b[i]-'a'; } ll ret=0; for(i=1;i<=cnt;i++) { int l=1,r=min(i,cnt-i+1),ma; while(l<=r) { int mid=l+r>>1; if(check(mid,i-mid+1,i+mid-1,h1,h3)&&check(mid,i-mid+1,i+mid-1,h2,h4)) { ma=mid; l=mid+1; } else r=mid-1; } ll now=pre[i+ma-1]-pre[i-ma]; if(b[i+ma]==b[i-ma]&&i-ma>=1&&i+ma<=cnt)now+=2*min(a[i-ma],a[i+ma]); ret=max(ret,now); } printf("%lld ",ret); } return 0; }