[loj2479]制胡窜

建立后缀自动机,并用预处理出right集合,考虑对于一个长度为$len$且$right=\left\{ r_{1},r_{2}, \cdots ,r_{k} \right\}(r_{1}<r_{2}<\cdots<r_{k})$(设字符串下标从1开始),有多少种方案使得其不合法(再用$c(n,2)$减去下面的$ans$)
这就意味着对于一个任意一个$r$,都有$r-len+1\le i<r$或$r-len+1\le j<r$,分类讨论:
1.存在$r_{a}<r_{b}<r_{c}$,满足$r_{b}-len+1\ge r_{a}$且$r_{c}-len+1\ge r_{b}$,那么a,b和c无法同时满足两个,即无解
2.满足$r_{k}-len+1<r_{1}$,那么令$s=r_{1}-(r_{k}-len+1)$,则$ans=C(s,2)+s\cdot (n-1-s)+\sum_{i=1}^{k-1}(r_{i+1}-r_{i})^{2}$
3.两种情况都不满足,必然有i隔断了$r1,r2,\cdots,r_{a}$,j隔断了$r_{b},r_{b+1},\cdots,r_{k}$($b\le a+1$)(令a和b分别为最大和最小的a和b),令A和B分别表示最大可能的a和最小可能的b(必然有$B\le A+1$),计算方案数:
$ans=\sum_{a=1}^{A}\sum_{b=B}^{k}[b\le a+1]\begin{pmatrix} \begin{Bmatrix} r_{1}-(r_{A}-len+1)\ (a=A) \\ r_{a+1}-r_{a}\ (a<A) \end{Bmatrix}\end{pmatrix} \begin{pmatrix} \begin{Bmatrix} r_{B}-(r_{k}-len+1)\ (b=B) \\ r_{b}-r_{b-1}\ (b>B)\end{Bmatrix}\end{pmatrix}$
然后a和b的枚举范围修改为$ans=\sum_{a=B-1}^{A}\sum_{b=B}^{a+1}\cdots$,这样就不需要$b\le a+1$的判断了
再调换枚举顺序,考虑$\sum_{b=B}^{i+1}\begin{pmatrix} \begin{Bmatrix} r_{B}-(r_{k}-len+1)\ (b=B) \\ r_{b}-r_{b-1}\ (b>B)\end{Bmatrix}\end{pmatrix})=r_{a+1}-r_{k}+len-1$
代入原式,得到$ans=\sum_{a=B-1}^{A}\begin{pmatrix} \begin{Bmatrix} r_{1}-(r_{A}-len+1)\ (a=A) \\ r_{a+1}-r_{a}\ (a<A)\end{Bmatrix}\end{pmatrix}(r_{a+1}-r_{k}+len-1)$
再对$a$分类讨论,即$ans=(r_{1}-(r_{A}-len+1))(r_{A+1}-r_{k}+len-1)+\sum_{a=B-1}^{A}(r_{a+1}-r_{a})(r_{a+1}-r_{k}+len-1)$
最后,我们相当于要在求right集合的时侯用线段树顺便维护:1.区间和;2.区间平方和;3.区间相邻两数乘积和;4.区间左右端点;5.区间中数的个数,然后就可以算出上面的式子了
 
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 200005
  4 #define ll long long
  5 #define L ls[k]
  6 #define R rs[k]
  7 #define mid (l+r>>1)
  8 struct ji{
  9     int nex,to;
 10 }edge[N<<1];
 11 struct node{
 12     int l,r;
 13     ll mul,sum[3];
 14 }tr[N*20];
 15 int V,VV,E,las,n,m,l,r,a[N],mx[N],nex[N],head[N],rt[N],ls[N*20],rs[N*20],ch[N][11],f[N][21];
 16 char s[N];
 17 ll C(int n){
 18     return n*(n-1LL)/2;
 19 }
 20 ll sqr(int n){
 21     return 1LL*n*n;
 22 }
 23 node up(node x,node y){
 24     node k;
 25     k.l=min(x.l,y.l);
 26     k.r=min(x.r,y.r);
 27     k.mul=x.mul+y.mul;
 28     if (x.sum[0]*y.sum[0])x.mul+=1LL*x.r*y.l;
 29     for(int i=0;i<3;i++)k.sum[i]=x.sum[i]+y.sum[i];
 30     return k;
 31 }
 32 void update(int &k,int l,int r,int x){
 33     if (!k)tr[k=++VV]=tr[0];
 34     if (l==r){
 35         tr[k].l=tr[k].r=tr[k].sum[1]=x;
 36         tr[k].sum[0]=1;
 37         tr[k].sum[2]=1LL*x*x;
 38         return;
 39     }
 40     if (x<=mid)update(L,l,mid,x);
 41     else update(R,mid+1,r,x);
 42     tr[k]=up(tr[L],tr[R]); 
 43 }
 44 int merge(int k1,int k2){
 45     if (k1*k2==0)return k1+k2;
 46     int k=++VV;
 47     L=merge(ls[k1],ls[k2]);
 48     R=merge(rs[k1],rs[k2]);
 49     tr[k]=up(tr[L],tr[R]); 
 50     return k;
 51 }
 52 int query1(int k,int l,int r,int x){//最后一个比x小 
 53     if (l==r)return l;
 54     if (tr[R].l>=x)return query1(L,l,mid,x);
 55     return query1(R,mid+1,r,x);
 56 }
 57 int query2(int k,int l,int r,int x){//第一个比x大 
 58     if (l==r)return l;
 59     if (tr[l].r>x)return query2(L,l,mid,x);
 60     return query2(R,mid+1,r,x);
 61 }
 62 node query(int k,int l,int r,int x,int y){
 63     if ((!k)||(l>y)||(x>r))return tr[0];
 64     if ((x<=l)&&(r<=y))return tr[k];
 65     return up(query(L,l,mid,x,y),query(R,mid+1,r,x,y));
 66 }
 67 void add(int c){
 68     int p=las,np=las=++V;
 69     mx[np]=mx[p]+1;
 70     while ((p)&&(!ch[p][c])){
 71         ch[p][c]=np;
 72         p=nex[p];
 73     }
 74     if (!p)nex[np]=1;
 75     else{
 76         int q=ch[p][c];
 77         if (mx[q]==mx[p]+1)nex[np]=q;
 78         else{
 79             int nq=++V;
 80             mx[nq]=mx[p]+1;
 81             nex[nq]=nex[q];
 82             memcpy(ch[nq],ch[q],sizeof(ch[q]));
 83             nex[q]=nex[np]=nq;
 84             while ((p)&&(ch[p][c]==q)){
 85                 ch[p][c]=nq;
 86                 p=nex[p];
 87             }
 88         }
 89     }
 90 }
 91 void add(int x,int y){
 92     edge[E].nex=head[x];
 93     edge[E].to=y;
 94     head[x]=E++;
 95 }
 96 void dfs(int k,int fa){
 97     f[k][0]=fa;
 98     for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1];
 99     for(int i=head[k];i!=-1;i=edge[i].nex)
100         if (edge[i].to!=fa){
101             dfs(edge[i].to,k);
102             rt[k]=merge(rt[k],rt[edge[i].to]);
103         }
104 }
105 int find(int k,int len){
106     for(int i=20;i>=0;i--)
107         if (mx[f[k][i]]>=len)k=f[k][i];
108     return k;
109 }
110 ll query(int k,int len){
111     int a=query1(k,1,n,tr[k].l+len-1),b=query2(k,1,n,tr[k].r-len+1);
112     if (a+1<b)return 0;
113     if (tr[k].r-len+1<tr[k].l){
114         int s=tr[k].l-(tr[k].r-len+1);
115         return C(s)+s*(n-1LL-s)+2*tr[k].sum[2]-2*tr[k].mul-sqr(tr[k].l)-sqr(tr[k].r); 
116     }
117     int aa=query2(k,1,n,a),bb=query1(k,1,n,b);
118     return 1LL*(tr[k].l-(a-len+1))*(aa-tr[k].r+len-1)+(bb-aa)*(tr[k].r-len+1LL)+query(k,1,n,b,aa).sum[2]-query(k,1,n,bb,aa).mul;
119 }
120 int main(){
121     scanf("%d%d%s",&n,&m,s);
122     V=las=1;
123     tr[0].l=n+1;
124     for(int i=0;i<n;i++){
125         add(s[i]-'0');
126         a[i+1]=las;
127         update(rt[las],1,n,i+1);
128     }
129     memset(head,-1,sizeof(head));
130     for(int i=1;i<=V;i++)add(nex[i],i);
131     for(int i=1;i<=m;i++){
132         scanf("%d%d",&l,&r);
133         printf("%lld\n",C(n+1)-query(rt[find(a[r],r-l+1)],r-l+1));
134     }
135 }
View Code

 

posted @ 2020-07-21 10:21  PYWBKTDA  阅读(177)  评论(0编辑  收藏  举报