CF1286F Fedya the Potter Strikes Back

Fedya the Potter Strikes Back

给定一个字符串 S 和权值数组 W

定义 S 的一个子串是好的,当且仅当这个子串等于 S 的某个前缀

一个子串 S[L : R] 的权值是 W[L...R] 的最小值

对于 S 的每个前缀,求他的所有好的子串的权值之和

N ≤ 105

题解

https://www.cnblogs.com/asuldb/p/12261061.html

不难发现这个好的子串其实就是border,这个动态加入我们只需要考虑答案的增量即可。

考虑从i−1加一个字符ci之后border的变化,如果x在S[1,i−1]是一个border,那么如果Sx+1=ci,那么x+1就是S[1,i]的border,反之则不是;特殊地,当S1=ci时,1会成为一个border。

我们发现这个变化比较简单,于是我们只需要考虑border集合的变化即可。

加入新的border特判一下即可;考虑如何删掉加入ci后不合法的border,注意到x不合法当且仅当Sx+1≠ci,于是我们记x的颜色为Sx+1,我们利用kmp构建一棵fail树,对于每一种颜色分别维护每个节点往上第一个该颜色的祖先;这样我们枚举x的颜色,从i−1暴力跳着删除即可;删除的时候贡献是一个区间min,对wi动态构建一个st表即可;由于每个点只会被删除一次,所以复杂度是正确的。

之后对于合法的border,其只新增了一个wi,也就是贡献需要对wi取一个min,于是我们需要一个数据结构支持整体求和、将所有数和wi取min、插入以及删除。只需要一个std::map暴力修改即可。由于一次插入的数之后被最多被暴力取min一次,复杂度是均摊正确的。

扫描二维码关注公众号,回复: 9289182 查看本文章

之后答案可能是n2×wi级别,于是可能会爆long long,所以统计答案的时候需要一个高精。Codeforces不支持__int128(大概它是32位电脑),所以只好手写pair<long long,long long>

CO int N=6e5+10;
char s[N];int w[N];

namespace ST{ // sparse table
    int lg[N],mn[N][20];
    
    void init(int n){
        for(int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
    }
    void insert(int p,int v){
        mn[p][0]=v;
        for(int i=1;i<=lg[p];++i)
            mn[p][i]=min(mn[p][i-1],mn[p-(1<<(i-1))][i-1]);
    }
    int query(int l,int r){
        int k=lg[r-l+1];
        return min(mn[r][k],mn[l+(1<<k)-1][k]);
    }
}

namespace BT{ // balanced tree
    map<int,int> cnt;
    int64 sum;
    
    void insert(int v,int c){
        cnt[v]+=c;
        sum+=(int64)v*c;
    }
    int query(int v){ // >v
        int siz=0;
        vector<int> del;
        for(map<int,int>::iterator i=cnt.upper_bound(v);i!=cnt.end();++i){
            siz+=i->second;
            del.push_back(i->first);
            sum-=(int64)i->first*i->second;
        }
        for(int x:del) cnt.erase(x);
        return siz;
    }
}

int nxt[N],col[N],fa[N][26];

CO int64 mod=1e18;
IN int operator%(CO pair<int64,int64>&x,int y){
    return (x.first%y+(x.second%y)*(mod%y))%y;
}
IN pair<int64,int64>&operator+=(pair<int64,int64>&x,int64 y){
    x.first+=y,x.second+=x.first/mod,x.first%=mod;
    return x;
}
IN void writeln(CO pair<int64,int64> x){
    if(x.second) printf("%lld%018lld\n",x.second,x.first);
    else printf("%lld\n",x.first);
}

int main(){
    int n=read<int>();
    ST::init(n);
    pair<int64,int64> ans={0,0};
    for(int i=1;i<=n;++i){
        scanf("%s",s+i),read(w[i]);
        s[i]=(s[i]-'a'+ans%26)%26+'a',w[i]^=ans%(1<<30);
        ST::insert(i,w[i]);
        ans+=ST::query(1,i);
        if(i==1){
            writeln(ans);
            continue;
        }
        int j=nxt[i-1];
        while(j and s[j+1]!=s[i]) j=nxt[j];
        nxt[i]=j+(s[j+1]==s[i]);
        col[i-1]=s[i]-'a';
        copy(fa[nxt[i]],fa[nxt[i]]+26,fa[i]);
        fa[i][col[nxt[i]]]=nxt[i];
        if(s[1]==s[i]) BT::insert(w[i],1);
        for(int c=0;c<26;++c)if(c!=s[i]-'a')
            for(int j=fa[i-1][c];j;j=fa[j][c])
                BT::insert(ST::query(i-j,i-1),-1);
        BT::insert(w[i],BT::query(w[i]));
        ans+=BT::sum;
        writeln(ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12336668.html