2018 ICPC 南京 M题 Mediocre String Problem ——Gym - 101981M

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;
}

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/90142634