[HAOI2017] 供给侧改革

给定一个随机的 (01) 串,设 (f(l,r)) 表示在 (max_{lleq p<q leq r} LCP(s[pdots n],s[qdots n])),有 (q) 个询问,每个询问给定 ([L,R]),求 (sum_{i=L}^{R-1} f(i,R))

Solution

考虑到随机的 (01) 串,两个后缀的 LCP 长度不会太长

那么我们要比较两个后缀,只要去比较它的前 (k) 个字符,就可以基本确定 LCP

考虑将询问离线,按右端点排序,然后升序扫描

在 Trie 里记录每一个节点被到达的最晚时间,那么我们每次新插入一个后缀 (i),就可以更新计算出对于每一个 (len),使得 (LCP(j,i) geq len) 的最大的 (j),不妨将这个数组记为 (ans[len])

(ans) 数组一定是单调不严格递减的,于是我们只要扫一遍 (ans) 数组即可统计答案

#include <bits/stdc++.h>
using namespace std;

const int N = 200005;

struct query {
    int l,r,id;
    bool operator < (const query &b) {
        return r < b.r;
    }
} qu[N];

int n,q,ans[44],res[N];
char s[N];

namespace trie {
    int ch[N*44][2], las[N*44], ind=1;
    void insert(char *s,int l,int r) {
        int p=1;
        for(int i=l;i<=r;i++) {
            int x=s[i]-'0';
            ans[i-l]=max(ans[i-l],las[p]);
            las[p]=l;
            if(!x) {
                if(ch[p][0]==0) ch[p][0]=++ind, las[ind]=-1e9;
                p=ch[p][0];
            }
            else {
                if(ch[p][1]==0) ch[p][1]=++ind, las[ind]=-1e9;
                p=ch[p][1];
            }
        }
        int i=r+1;
        ans[i-l]=max(ans[i-l],las[p]);
        las[p]=l;
    }
}

void solve() {
    ios::sync_with_stdio(false);
    cin>>n>>q;
    cin>>s+1;
    for(int i=1;i<=q;i++) cin>>qu[i].l>>qu[i].r, qu[i].id=i;
    sort(qu+1,qu+q+1);
    int pos=0;
    for(int i=1;i<=q;i++) {
        while(pos<qu[i].r) {
            ++pos;
            trie::insert(s,pos,min(n,pos+40));
        }
        for(int j=1;j<=40;j++)
            res[qu[i].id]+=j*max(0,min(ans[j],pos-1)-max(ans[j+1],qu[i].l-1));
    }
    for(int i=1;i<=q;i++) cout<<res[i]<<endl;
}

signed main() {
    solve();
}

原文地址:https://www.cnblogs.com/mollnn/p/12407913.html