zoukankan      html  css  js  c++  java
  • CF1286E Fedya the Potter Strikes Back

    只需考虑每次加入后答案的增量,即增加的子串的答案。

    发现有贡献的子串为 ( ext{border}),那么每次就只需维护 ( ext{border}) 集合的变化。若子串 ([1,pos]) 为子串 ([1,i]) 的一个 ( ext{border}),则 (s_{pos+1}=s_{i+1}) 时,子串 ([1,pos+1]) 就仍为子串 ([1,i+1]) 的一个合法的 ( ext{border})

    考虑加入位置 (i) 后如何处理。若产生了新的 ( ext{border}),就直接加入,即 (s_1=s_i)。考虑如何删去不合法的 ( ext{border})。设位置 (i) 的颜色为 (s_i+1),加入后不合法的 ( ext{border}) 为位置 (i)( ext{border}) 结尾位置的颜色不一样。那么用 (kmp) 的失配指针构建一棵树,在每个节点上对每一种颜色都维护出最近的该颜色的祖先,每次就在树上删去和当前加入的颜色不同的 ( ext{border}),删除时需要查询区间最小值,用线段树维护即可。因为每个 ( ext{border}) 只会被删除一次且每次最多加入一个 ( ext{border}),因此复杂度有保证。维护 ( ext{border}) 的权值时要做到对所有的权值和 (w_i)(min),这里用 (map) 维护每个权值的出现次数,修改就暴力修改即可。因为每个加入的权值最多被暴力取 (min) 一次,因此复杂度有保证。

    时间复杂度为 (O(n log n))

    #include<bits/stdc++.h>
    #define maxn 600010
    #define maxm 2400010
    #define inf 2000000000
    #define mod 1000000000000000000
    #define ls (cur<<1)
    #define rs (cur<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,root=1,pos;
    ll val;
    int s[maxn],w[maxn],nxt[maxn],col[maxn],fa[maxn][28],st[maxn],mn[maxm];
    char c[5];
    map<ll,int> mp;
    pair<ll,ll> ans;
    pair<ll,ll> operator +(const pair<ll,ll> &x,const ll &y)
    {
        return make_pair((x.first+y)%mod,x.second+(x.first+y)/mod);
    }
    ll operator %(const pair<ll,ll> &x,const ll &p)
    {
        return (x.first%p+(x.second%p)*(mod%p)%p)%p;
    }
    void write(pair<ll,ll> x)
    {
        if(x.second) printf("%lld%018lld
    ",x.second,x.first);
        else printf("%lld
    ",x.first);
    }
    void modify(int l,int r,int pos,int v,int cur)
    {
        if(l==r)
        {
            mn[cur]=v;
            return;
        }
        if(pos<=mid) modify(l,mid,pos,v,ls);
        else modify(mid+1,r,pos,v,rs);
        mn[cur]=min(mn[ls],mn[rs]);
    }
    int query(int L,int R,int l,int r,int cur)
    {
        if(L<=l&&R>=r) return mn[cur];
        int v=inf;
        if(L<=mid) v=min(v,query(L,R,l,mid,ls));
        if(R>mid) v=min(v,query(L,R,mid+1,r,rs));
        return v;
    }
    void add(ll x,int v)
    {
        mp[x]+=v,val+=x*v;
    }
    int update(int x)
    {
        int cnt=0,top=0;
        for(map<ll,int>::iterator it=mp.upper_bound(x);it!=mp.end();++it)
            st[++top]=it->first,cnt+=it->second,val-=it->first*it->second;
        while(top) mp.erase(st[top--]);
        return cnt;
    }
    int main()
    {
        read(n),scanf("%s",c),s[1]=c[0]-'a',read(w[1]);
        modify(1,n,1,w[1],root),ans=ans+w[1],write(ans);
        for(int i=2;i<=n;++i)
        {
            scanf("%s",c),read(w[i]);
            s[i]=(c[0]-'a'+ans%26)%26,w[i]^=ans%(1<<30);
            if(s[1]==s[i]) add(w[i],1);
            modify(1,n,i,w[i],root),ans=ans+query(1,i,1,n,root),pos=nxt[i-1];
            while(pos&&s[pos+1]!=s[i]) pos=nxt[pos];
            nxt[i]=pos+(s[pos+1]==s[i]),col[i-1]=s[i];
            for(int j=0;j<26;++j) fa[i][j]=fa[nxt[i]][j];
            fa[i][col[nxt[i]]]=nxt[i];
            for(int c=0;c<26;++c)
            {
                if(c==s[i]) continue;
                for(int j=fa[i-1][c];j;j=fa[j][c])
                    add(query(i-j,i-1,1,n,root),-1);
            }
            add(w[i],update(w[i])),ans=ans+val,write(ans);
        }
        return 0;
    }
    
  • 相关阅读:
    iOS设备后台播放音乐方法
    iOS 编译64位FFMPEG
    os8 location authorization 错误.
    IOS 使用新浪微博SDK
    IOS 解析歌词lrc
    IOS 通过button获取cell
    IOS 解析XML文档
    OC .(点)与->(箭头)用法区别
    黑苹果安装合集
    Hello,World
  • 原文地址:https://www.cnblogs.com/lhm-/p/13773921.html
Copyright © 2011-2022 走看看