题解:
后缀数组
然后把读入的内容去重,按照rank排序
然后用单调栈处理一下
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=500010; const ll M=23333333333333333ll; int r[N],ra[N],rb[N],a,st[N],h[N],sa[N],rank[N],n,m,Q; int q[N],t,ls[N],rs[N],f[N][20],Log[N],vis[N],v[N],s[N]; ll ans; char str[N]; void build() { int *x=ra,*y=rb; for (int i=0;i<n;i++)st[x[i]=r[i]]++; for (int i=1;i<m;i++)st[i]+=st[i-1]; for (int i=n-1;i>=0;i--) sa[--st[x[i]]]=i; for (int j=1,p=1;p<n;j<<=1,m=p) { p=0; for (int i=n-j;i<n;i++)y[p++]=i; for (int i=0;i<n;i++) if (sa[i]>=j)y[p++]=sa[i]-j; for (int i=0;i<m;i++)st[i]=0; for (int i=0;i<n;i++)st[x[y[i]]]++; for (int i=1;i<m;i++)st[i]+=st[i-1]; for (int i=n-1;i>=0;i--)sa[--st[x[y[i]]]]=y[i]; swap(x,y);x[sa[0]]=0; for (int i=p=1;i<n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++; } for (int i=1;i<n;i++)rank[sa[i]]=i; for (int i=0,k=0;i<n-1;h[rank[i++]]=k) { if (k)k--; for (int j=sa[rank[i]-1];r[i+k]==r[j+k];k++); } } int cmp(int a,int b){return rank[a]<rank[b];} int query(int a,int b) { int k=Log[b-a+1]; return min(f[a][k],f[b-(1<<k)+1][k]); } int main() { scanf("%d%d%s",&n,&Q,str); for (int i=0;i<n;i++)r[i]=str[i]-'a'+1; n++;m=27;build();n--; for (int i=1;i<=n;i++)f[i][0]=h[i]; for (int j=1;(1<<j)<n;j++) for (int i=1;i+(1<<j)-1<=n;i++)f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]); for (int i=2;i<=n;i++)Log[i]=Log[i>>1]+1; while (Q--) { scanf("%d",&a); for (int j=1;j<=a;j++) { scanf("%d",&v[j]); v[j]--; if (vis[v[j]])j--,a--; vis[v[j]]=1; } sort(v+1,v+a+1,cmp); for (int j=1;j<a;j++)s[j]=query(rank[v[j]]+1,rank[v[j+1]]); s[0]=s[a]=-1;q[1]=0;t=1; for (int j=1;j<a;j++) { while (t&&s[q[t]]>s[j])t--; ls[j]=q[t],q[++t]=j; } t=1,q[1]=a; for (int j=a-1;j>0;j--) { while (t&&s[q[t]]>=s[j])t--; rs[j]=q[t],q[++t]=j; } ans=0; for (int j=1;j<a;j++)ans=(ans+(ll)(j-ls[j])*(rs[j]-j)*s[j])%M; printf("%lld\n",ans); for (int j=1;j<=a;j++)vis[v[j]]=0; } }