uoj #103. 【APIO2014】Palindromes
#103. 【APIO2014】Palindromes
给你一个由小写拉丁字母组成的字符串 ss。我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这个子串的长度。
对于给你的这个字符串 ss,求所有回文子串中的最大存在值。
输入格式
一行,一个由小写拉丁字母(a~z)组成的非空字符串 ss。
输出格式
输出一个整数,表示所有回文子串中的最大存在值。
样例一
input
abacaba
output
7
explanation
用 ∣s∣∣s∣ 表示字符串 ss 的长度。
一个字符串 s1s2…s∣s∣s1s2…s∣s∣ 的子串是一个非空字符串 sisi+1…sjsisi+1…sj,其中 1≤i≤j≤∣s∣1≤i≤j≤∣s∣。每个字符串都是自己的子串。
一个字符串被称作回文串当且仅当这个字符串从左往右读和从右往左读都是相同的。
这个样例中,有 77 个回文子串 a,b,c,aba,aca,bacab,abacaba。他们的存在值分别为 4,2,1,6,3,5,74,2,1,6,3,5,7。
所以回文子串中最大的存在值为 77。
样例二
input
www
output
4
限制与约定
第一个子任务共 8 分,满足 1≤∣s∣≤1001≤∣s∣≤100。
第二个子任务共 15 分,满足 1≤∣s∣≤10001≤∣s∣≤1000。
第三个子任务共 24 分,满足 1≤∣s∣≤100001≤∣s∣≤10000。
第四个子任务共 26 分,满足 1≤∣s∣≤1000001≤∣s∣≤100000。
第五个子任务共 27 分,满足 1≤∣s∣≤3000001≤∣s∣≤300000。
时间限制:1s1s
空间限制:256MB
/* 暴力枚举所有子串,hash判断是否回文,kmp查找出现次数 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 310000 using namespace std; char s1[maxn],s2[maxn]; int l1,l2,nxt[maxn]; unsigned long long h1[maxn],h2[maxn],base[maxn]; void getnxt(){ nxt[0]=-1;nxt[1]=0; for(int i=2;i<=l2;i++){ int j=nxt[i-1]; while(j&&s2[i]!=s2[j+1])j=nxt[j]; if(s2[i]==s2[j+1])nxt[i]=j+1; else nxt[i]=0; } } int kmp(){ int i=0,j=0,cnt=0; while(i<=l1&&j<=l2){//l1是长的,l2是短的 if(s1[i]==s2[j]||j==0)i++,j++; else j=nxt[j-1]+1; if(j==l2+1){ cnt++; j=nxt[j-1]+1; } } return cnt; } unsigned long long find1(int l,int r){ return h1[r]-h1[l-1]*base[r-l+1]; } unsigned long long find2(int l,int r){ return h2[l]-h2[r+1]*base[r-l+1]; } int main(){ scanf("%s",s1+1);l1=strlen(s1+1); base[0]=1; for(int i=1;i<=l1;i++)h1[i]=h1[i-1]*123+s1[i]-'a',base[i]=base[i-1]*123; for(int i=l1;i>=1;i--)h2[i]=h2[i+1]*123+s1[i]-'a'; long long ans=0; for(int i=1;i<=l1;i++){ l2=0; for(int j=i;j<=l1;j++){ s2[++l2]=s1[j]; if(find1(i,j)==find2(i,j)){//是回文串 getnxt(); int cnt=kmp(); ans=max(ans,1LL*cnt*(j-i+1)); } } } cout<<ans; return 0; }
#include<iostream> #include<cstdio> #include<cstring> #define maxn 300010 using namespace std; char s[maxn]; int fail[maxn],nxt[maxn][26],cnt[maxn],len[maxn],str[maxn],last,tot,n,sz=-1; int creat(int l){ len[++sz]=l;return sz; } int getfail(int x){ while(str[n-len[x]-1]!=str[n])x=fail[x]; return x; } void Insert(int c){ str[++n]=c; int cur=getfail(last),now; if(!nxt[cur][c]){ now=creat(len[cur]+2); fail[now]=nxt[getfail(fail[cur])][c]; nxt[cur][c]=now; } last=nxt[cur][c]; cnt[last]++; } void count(){ for(int i=sz;i>=0;i--)cnt[fail[i]]+=cnt[i]; } long long solve(){ long long res=0; for(int i=sz;i>1;i--) res=max(res,1LL*len[i]*cnt[i]); return res; } void prepare(){ creat(0); creat(-1); last=0; str[0]=str[1]=-1; fail[0]=1; } int main(){ freopen("Cola.txt","r",stdin); scanf("%s",s); prepare(); int len=strlen(s); for(int i=0;i<len;i++) Insert(s[i]-'a'); count(); cout<<solve(); return 0; }