http://fastvj.rainng.com/problem/Gym-101981M
http://codeforces.com/gym/101981/attachments
题意:给你两个串s和t串,从s串中选出一个子串,然后再t串中取一个前缀出来,组合出是回文串一共有多少中方法。
做法:这道题,我训练的时候想到了用找出t串在s串中匹配的位置,然后找出s串中每一个起点开始的回文串的数量。
关于回文串的数量,这个可以用马拉车算法解决,这个训练的由于第一次这样写,还是调了很久,关于怎么处理还是等会儿看代码。
关于前面的一部分,先想的是吧t串反转拼接匹配,用后缀数组,然后一会儿过了样列WA了,后来想了如果把s串反转,再把t串拼接,然后求LCP就可以了,结果交上去T了,,,,,然后果断换了一个O(N)的后缀数组板子,结果刚刚卡过去。。。
还有其他解法,后面在更新吧
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const double eps=1e-8;
const int N=2e6+10;
///int s[N],sa[N],c[N],t1[N],t2[N],n,rk[N],height[N];
int dmin[N][25];
inline int minn(int a,int b)
{
return a>=b?b:a;
}
inline int maxn(int a,int b)
{
return a>=b?a:b;
}
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int sa[N],rk[N],height[N],s[N];
int wa[N],wb[N],wv[N],wss[N];
inline int c0(int *r,int a,int b){
return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];
}
inline int c12(int k,int *r,int a,int b){
if(k==2)
return r[a]<r[b]||(r[a]==r[b]&&c12(1,r,a+1,b+1));
else return r[a]<r[b]||(r[a]==r[b]&&wv[a+1]<wv[b+1]);
}
inline void ssort(int *r,int *a,int *b,int n,int m){
int i;
for(i=0;i<n;i++)wv[i]=r[a[i]];
for(i=0;i<m;i++)wss[i]=0;
for(i=0;i<n;i++)wss[wv[i]]++;
for(i=1;i<m;i++)wss[i]+=wss[i-1];
for(i=n-1;i>=0;i--)
b[--wss[wv[i]]]=a[i];
}
inline void dc3(int *r,int *sa,int n,int m){
int i,j,*rn=r+n;
int *san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
r[n]=r[n+1]=0;
for(i=0;i<n;i++)if(i%3!=0)wa[tbc++]=i;
ssort(r+2,wa,wb,tbc,m);
ssort(r+1,wb,wa,tbc,m);
ssort(r,wa,wb,tbc,m);
for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
if(p<tbc)dc3(rn,san,tbc,p);
else for(i=0;i<tbc;i++)san[rn[i]]=i;
for(i=0;i<tbc;i++)if(san[i]<tb)wb[ta++]=san[i]*3;
if(n%3==1)wb[ta++]=n-1;
ssort(r,wb,wa,ta,m);
for(i=0;i<tbc;i++)wv[wb[i]=G(san[i])]=i;
for(i=0,j=0,p=0;i<ta&&j<tbc;p++)
sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
for(;i<ta;p++)sa[p]=wa[i++];
for(;j<tbc;p++)sa[p]=wb[j++];
}
inline void da(int n,int m){
for(int i=n;i<n*3;i++)s[i]=0;
dc3(s,sa,n+1,m);
int i,j,k=0;
for(i=0;i<=n;i++)rk[sa[i]]=i;
for(i=0;i<n;i++){
if(k)k--;
j=sa[rk[i]-1];
while(s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
}
void print(int n){
cout<<"sa[] ";
for(int i=0;i<=n;i++)cout<<sa[i]<<" ";cout<<endl;
cout<<"rank[] ";
for(int i=0;i<=n;i++)cout<<rk[i]<<" ";cout<<endl;
cout<<"height[] ";
for(int i=0;i<=n;i++)cout<<height[i]<<" ";cout<<endl;
}
int n;
inline void initMin()
{
for(int i=1; i<=n; i++)
dmin[i][0]=height[i];
for(int j=1; (1<<j)<=n; j++)
for(int i=1; i+(1<<j)-1<=n; i++)
dmin[i][j]=minn(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
}
inline int RMQ(int L,int R)
{
int k=0;
while((1<<(k+1))<=R-L+1)
k++;
return minn(dmin[L][k],dmin[R-(1<<k)+1][k]);
}
inline int LCP(int i,int j)
{
int L=rk[i],R=rk[j];
if(L>R) swap(L,R);
L++;
return RMQ(L,R);
}
char str[N],tstr[N],s_new[N];
int p[N];
inline int init()
{
int len=strlen(str);
s_new[0]='$';
s_new[1]='#';
int j=2;
for(int i=0;i<len;i++)
{
s_new[j++]=str[i];
s_new[j++]='#';
}
s_new[j]='\0';
return j;
}
int d[N];
inline int Manacher()
{
int len=init();
int max_len=-1;
int id,mx=0;
for(int i=1;i<len;i++)
{
if(i<mx) p[i]=minn(p[2*id-i],mx-i);
else p[i]=1;
while(s_new[i-p[i]]==s_new[i+p[i]]) p[i]++;
if(mx<i+p[i]) id=i,mx=i+p[i];
max_len=maxn(max_len,p[i]-1);
}
for(int i=2;i<len;i++)
{
if(s_new[i]=='#'&&p[i]==1) continue;
int x=i/2-p[i]/2+1;
int y=x+i/2+p[i]/2-!(i&1);
d[x]++;
d[y/2+1]--;
}
return max_len;
}
int sum[N];ll ans=0;
int main()
{
scanf("%s%s",str,tstr);
Manacher();
int len=strlen(str);
for(int i=1;i<=len;i++) d[i]+=d[i-1];
d[len+1]=0;
for(int i=len-1;i>=0;i--) s[n++]=str[i]-'a'+1;
s[n++]=30;
int tlen=strlen(tstr);
for(int i=0;i<tlen;i++) s[n++]=tstr[i]-'a'+1;
s[n++]=0;
da(n-1,31);
initMin();
for(int i=0,j=len;i<len;i++,j--)
{
int k=LCP(i,len+1);
if(k) ans+=1LL*k*d[j+1];
}
printf("%lld\n",ans);
return 0;
}