#include using namespace std; #define int long long #define rep(i,n) for(int i=0;i<(n);i++) #define pb push_back #define all(v) (v).begin(),(v).end() #define fi first #define se second typedef vectorvint; typedef pairpint; typedef vectorvpint; templateinline void chmin(A &a,B b){if(a>b)a=b;} templateinline void chmax(A &a,B b){if(a&v,vector&bucket){ fill(bucket.begin(),bucket.end(),0); for(int i=0;i&v,vector&bucket){ fill(bucket.begin(),bucket.end(),0); for(int i=0;i&v,vector&sa,int mv,vector&bucket,vector&is_l){ create_begin_bucket(v,bucket); for(int i=0;i0&&is_l[sa[i]-1])sa[bucket[v[sa[i]-1]]++]=sa[i]-1; } void invert_induced_sort(vector&v,vector&sa,int mv,vector&bucket,vector&is_l){ create_end_bucket(v,bucket); for(int i=v.size()-1;i>=0;i--)if(sa[i]>0&&!is_l[sa[i]-1])sa[--bucket[v[sa[i]-1]]]=sa[i]-1; } vectorsa_is(vectorv,int mv){ if(v.size()==1)return vector(1,0); vectoris_l(v.size()); vectorbucket(mv+1); vectorsa(v.size(),-1); auto is_lms=[&](int x)->bool{return x>0&&is_l[x-1]&&!is_l[x];}; is_l[v.size()-1]=0; for(int i=v.size()-2;i>=0;i--)is_l[i]=v[i]>v[i+1]||(v[i]==v[i+1]&&is_l[i+1]); create_end_bucket(v,bucket); for(int i=0;iorder(v.size()); for(int i=0;inext_v(cur); cur=-1; int prev=-1; for(int i=0;i0&&is_lms(sa[i]+d))break; } if(diff){cur++;prev=sa[i];} next_v[order[sa[i]]]=cur; } vectorre_order(next_v.size()); for(int i=0;inext_sa=sa_is(next_v,cur); create_end_bucket(v,bucket); for(int i=0;i=0;i--)sa[--bucket[v[re_order[next_sa[i]]]]]=re_order[next_sa[i]]; induced_sort(v,sa,mv,bucket,is_l); invert_induced_sort(v,sa,mv,bucket,is_l); return sa; } void sa_is(string &s){ vectorv(s.size()+1); for(int i=0;i0)h--; for(;j+hdat; void init(vector &v){ for(N=1;N=0;i--)dat[i]=min(dat[i*2+1],dat[i*2+2]); } int get_min(int a,int b,int k,int l,int r){ if(r<=a||b<=l)return 1001001001; if(a<=l&&r<=b)return dat[k]; return min(get_min(a,b,k*2+1,l,(l+r)/2),get_min(a,b,k*2+2,(l+r)/2,r)); } int get_min(int a,int b){return get_min(a,b,0,0,N);} }; class sparse_table{ vector >st; public: void init(vectorvec){ int b; for(b=0;(1<(1<vec){init(vec);} }; public: segtree st; string s; vectorsa,lcp,rank; void init(string &t){; s=t; sa_is(s); construct_lcp(); st.init(lcp); } SuffixArray(string &t){init(t);} SuffixArray(){} bool contain(string &t){ int lb=0,ub=s.size(); while(ub-lb>1){ int mid=(lb+ub)/2; if(s.compare(sa[mid],t.size(),t)<0)lb=mid; else ub=mid; } return s.compare(sa[ub],t.size(),t)==0; } int get_lcp(int i,int j){ assert(i!=j); if(rank[i]>rank[j])swap(i,j); return st.get_min(rank[i],rank[j]); } int operator[](const int idx)const{ return sa[idx]; } }; vint calcL(string s){ string S=string(1,s[0]); for(int i=1;i= 0 && i+j < S.size() && S[i-j] == S[i+j]) ++j; R[i] = j; int k = 1; while(i-k >= 0 && i+k < S.size() && k+R[i-k] < j) R[i+k] = R[i-k], ++k; i += k; j -= k; } vint l(s.size()); for(int i=0;i>S>>T; vint l=calcL(S); SuffixArray s(S); vector>se(S.size()+1); string ST=S+"*"+T; SuffixArray st(ST); vint acc(S.size()+T.size()+114); for(int i=0;iS.size())acc[i+1]++; acc[i+1]+=acc[i]; } int ans=0; for(int i=0;i=l[i])continue; } if(it!=se[l[i]].begin()){ it--; if(s.st.get_min(*it,s.rank[i])>=l[i])continue; } int lef,rig; int lb=0,ub=st.rank[i]; while(ub-lb>1){ int mid=(ub+lb)/2; if(st.st.get_min(mid,st.rank[i])>=l[i])ub=mid; else lb=mid; } lef=ub; lb=st.rank[i],ub=st.sa.size(); while(ub-lb>1){ int mid=(ub+lb)/2; if(st.st.get_min(st.rank[i],mid)>=l[i])lb=mid; else ub=mid; } rig=ub; int x=acc[rig]-acc[lef]; int y=rig-lef-x; ans+=x*y; se[l[i]].insert(s.rank[i]); } cout<