FZOUTSY 题解

题意简述

给定一个长度为 \(n\) 的,由特定 \(7\) 种字符构成的字符串,有 \(m\) 次询问,每次询问需要求出编号在 \([l,r]\) 内的后缀中,有多少对后缀的最长公共前缀长度大于等于 \(k\)

题目分析

注意到在所有询问中,\(k\) 的值是一样的,所以我们可以考虑求出给定字符串中以第 \(i\) 个位置为开头,以第 \(i+k-1\) 个位置为结尾的区间的哈希值,随后,问题便转化为求在给定的区间内,有多少对数字相等。可以使用莫队解决。

代码

#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
inline int read(){register int t1=0,t2=0;register char x=getchar();while(x<'0' ||x>'9'){if(x=='-') t2|=1;x=getchar();}while(x>='0' && x<='9'){t1=(t1<<1)+(t1<<3)+(x^48),x=getchar();}return t2?-t1:t1;}
inline void write(int x){register int sta[105],top=0;if(x<0) putchar('-'),x=-x;do{sta[top++]=x%10,x/=10;}while(x);while(top) putchar(sta[--top]+48);}
const int base=131;
int n,m,k,f[3000005],p[3000005],a[3000005],tot,t[3000005],ans[3000005],l=1,r,now,cnt[3000005],temp;
char c[3000005];
struct que{
    int l,r,id;
}q[100005];
bool cmp(que x,que y){
    if(x.l/temp!=y.l/temp) return x.l<y.l;
    if((x.l/temp)&1) return x.r<y.r;
    return x.r>y.r;
}
inline void add(int x){
    now-=cnt[x]*cnt[x];
    cnt[x]++;
    now+=cnt[x]*cnt[x];
}
inline void del(int x){
    now-=cnt[x]*cnt[x];
    cnt[x]--;
    now+=cnt[x]*cnt[x];
}
signed main(){
    #ifdef cxy
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    #endif
    ios::sync_with_stdio(0);
    cin>>n>>m>>k;
    p[0]=1;
    for(int i=1;i<=n;i++){
        cin>>c[i];
        f[i]=f[i-1]*base+(c[i]-'a'+1);
        p[i]=p[i-1]*base;
    }
    for(int i=1;i+k-1<=n;i++){
        a[i]=f[i+k-1]-f[i-1]*p[i+k-1-i+1];
        t[i]=a[i];
        tot++;
    }
    sort(t+1,t+1+tot);
    temp=unique(t+1,t+1+tot)-t-1;
    for(int i=1;i<=tot;i++) a[i]=lower_bound(t+1,t+1+temp,a[i])-t;
    for(int i=1;i<=m;i++){
        cin>>q[i].l>>q[i].r;
        q[i].id=i;
        q[i].r=min(q[i].r,n-k+1);
        if(q[i].l>q[i].r){
            q[i].l=1;
            q[i].r=0;
        }
    }
    temp=sqrt(m);
    sort(q+1,q+1+m,cmp);
    for(int i=1;i<=m;i++){
        while(l>q[i].l) add(a[--l]);
        while(r<q[i].r) add(a[++r]);
        while(l<q[i].l) del(a[l++]);
        while(r>q[i].r) del(a[r--]);
        ans[q[i].id]=now-(q[i].r-q[i].l+1)>>1;
    }
    for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
	return 0;
}
posted @ 2024-11-27 21:05  ZnHF  阅读(30)  评论(0)    收藏  举报