题目大意
求一个字符串,从每一个位置分成两部分(当做两个字符串),求本质不同子串数量。
SAM
我们先有一个简单的思路。f[i]表示从i分成两部分的答案。
正难则反,求出原串本质不同子串数量,对于每个位置减去跨线且没在两边出现过的即可。
对于一个子串,如果其出现在原串中最大的右端点为mx,最小的右端点为mi,其长度为len。
如果mx-len>=mi,则因为其所有出现区间交为空,无论从哪个位置分开这个子串都会出现在其中一边。
如果
mx−len<mi
,那么f的[mx-len,mi-1]都可以加一,因为显然在区间交里都可以分离成功。
然而子串个数很多,怎么办呢?
考虑SAM,那么公用right集合的点被缩为一个点,枚举自动机上每个点,然后得到mx和mi(这里说一下mx和mi的求法,因为后缀自动机上一点的right集合是其parent树中子树的right集合的并,因此其mx等于其子树中mx的最大值,mi等于其子树中mi的最小值),同时要得到len的范围[l,r](后缀自动机上一个点的maxs就是step,mins就是其parent树父亲的maxs+1)
那么f的[mx-r+1,mx-l+1]是第一个+1,第二个+2,第三个+3……一直这样下去,然后f的[mx-l+2,mi-1]+r-l+1。
我们考虑线性做,可以设gi=fi-fi-1,那么区间加等差变成了区间+1,后面的平板只需要单点修改。区间加1可以通过开头挂+1结尾挂-1最后线性扫实现。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=500000+10,mo=1000000007;
int g[maxn*2][10],pre[maxn*2],step[maxn*2],mi[maxn*2],ma[maxn*2],mins[maxn*2],maxs[maxn*2],cnt[maxn*2],ad[maxn],f[maxn];
int a[maxn*2];
int i,j,k,l,r,t,n,m,tot,last,sum,ans;
char ch;
char get(){
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
return ch;
}
void add(int x){
int np=++tot,p=last;
mi[tot]=100000000;
step[np]=step[p]+1;
while (p>=0&&g[p][x]==0){
g[p][x]=np;
p=pre[p];
}
if (p==-1) pre[np]=0;
else{
int q=g[p][x];
if (step[q]==step[p]+1) pre[np]=q;
else{
int nq=++tot,i;
mi[tot]=100000000;
fo(i,0,9) g[nq][i]=g[q][i];
pre[nq]=pre[q];
pre[q]=nq;
step[nq]=step[p]+1;
pre[np]=nq;
while (p>=0&&g[p][x]==q){
g[p][x]=nq;
p=pre[p];
}
}
}
last=np;
}
int quicksortmi(int x,int y){
if (!y) return 1;
int t=quicksortmi(x,y/2);
t=(ll)t*t%mo;
if (y%2) t=(ll)t*x%mo;
return t;
}
int main(){
freopen("knight6.in","r",stdin);
scanf("%d",&n);
pre[0]=-1;
fo(i,1,n){
ch=get();
add(ch-'0');
ma[last]=mi[last]=i;
}
fo(i,1,tot) sum=(sum+step[i]-step[pre[i]])%mo;
/*fd(i,tot,1){
mi[pre[i]]=min(mi[pre[i]],mi[i]);
ma[pre[i]]=max(ma[pre[i]],ma[i]);
maxs[i]=step[i];
mins[i]=step[pre[i]]+1;
}*/
fo(i,0,tot) cnt[step[i]]++;
fo(i,0,step[last]) cnt[i]+=cnt[i-1];
fo(i,0,tot) a[cnt[step[i]]--]=i;
fd(i,tot+1,1){
mi[pre[a[i]]]=min(mi[pre[a[i]]],mi[a[i]]);
ma[pre[a[i]]]=max(ma[pre[a[i]]],ma[a[i]]);
maxs[a[i]]=step[a[i]];
mins[a[i]]=step[pre[a[i]]]+1;
}
fo(i,1,tot){
l=mins[i];r=maxs[i];
l=max(l,ma[i]-mi[i]+1);
if (l>r) continue;
ad[ma[i]-r+1]++;
ad[ma[i]-l+2]--;
f[mi[i]]-=(r-l+1);
}
k=0;
fo(i,1,n){
k=(k+ad[i])%mo;
f[i]=(f[i]+k);
}
fo(i,1,n) f[i]=(f[i]+f[i-1])%mo;
fo(i,1,n) f[i]=sum-f[i];
fo(i,1,n-1) ans=(ans+(ll)f[i]*quicksortmi(100013,n-i-1)%mo)%mo;
(ans+=mo)%=mo;
printf("%d\n",ans);
}