1 条题解
-
0
就是求出来SA,然后把给定的 t 个串按照 rk 排序。求出相邻两个LCP -> 求出序列间两两最小值 -> 考虑贡献,对于每个数求是哪些数对的最小值 -> 求每个数左边右边第一个比它小的数 -> 单调栈。
#pragma GCC optimize(2) #include<bits/stdc++.h> using std::min; using std::max; using std::swap; using std::vector; typedef double db; typedef long long ll; #define pb(A) push_back(A) #define pii std::pair<int,int> #define all(A) A.begin(),A.end() #define mp(A,B) std::make_pair(A,B) const int N=5e5+5; char s[N]; int l[N],r[N]; int stk[N],val[N],top; int n,m,lg[N],st[N][20]; int rk[N],height[N],sa[N]; int x[N],y[N],c[N],a[N*10]; bool cmp(int x,int y){ return rk[x]<rk[y]; } void gs(int num=0,int m=150){ for(int i=1;i<=n;i++) c[x[i]=s[i]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i;i--) sa[c[x[i]]--]=i; for(int k=1;num=0,k<=n;k<<=1){ for(int i=n-k+1;i<=n;i++) y[++num]=i; for(int i=1;i<=n;i++) if(sa[i]>k) y[++num]=sa[i]-k; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[x[i]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i]; swap(x,y);num=x[sa[1]]=1; for(int i=2;i<=n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]] and y[sa[i]+k]==y[sa[i-1]+k]?num:++num; if(num==n) return;m=num; } } void gh(int k=0){ for(int i=1;i<=n;i++) rk[sa[i]]=i; for(int i=1;i<=n;i++){ if(rk[i]==1) continue; if(k) k--; int j=sa[rk[i]-1]; while(i+k<=n and j+k<=n and s[i+k]==s[j+k]) k++; height[rk[i]]=k; } } void gt(){ for(int i=2;i<=n;i++) lg[i]=lg[i-1]+((1<<lg[i-1]+1)==i); for(int i=1;i<=n;i++) st[i][0]=height[i]; for(int i=1;i<=lg[n];i++) for(int j=1;j+(1<<i)-1<=n;j++) st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]); } int query(int x,int y){ if(x==y) return n-sa[x]+1; if(x>y) swap(x,y);x++; int k=lg[y-x+1]; return min(st[x][k],st[y-(1<<k)+1][k]); } int getint(){ int X=0,w=0;char ch=getchar(); while(!isdigit(ch))w|=ch=='-',ch=getchar(); while( isdigit(ch))X=X*10+ch-48,ch=getchar(); if(w) return -X;return X; } signed main(){ n=getint(),m=getint(); scanf("%s",s+1); gs(),gh(),gt(); while(m--){ int len=getint();ll ans=0; for(int i=1;i<=len;i++) a[i]=getint(); std::sort(a+1,a+1+len,cmp);len=std::unique(a+1,a+1+len)-a-1; for(int i=1;i<len;i++) val[i]=query(rk[a[i]],rk[a[i+1]]); for(int i=1;i<len;i++){ while(top and val[stk[top]]>=val[i]) r[stk[top--]]=i; stk[++top]=i; } while(top) r[stk[top--]]=len; for(int i=len-1;i;i--){ while(top and val[stk[top]]>val[i]) l[stk[top--]]=i; stk[++top]=i; } while(top) l[stk[top--]]=0; for(int i=1;i<len;i++) ans+=1ll*val[i]*(i-l[i])*(r[i]-i); printf("%lld\n",ans); } return 0; }
- 1
信息
- ID
- 5544
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者