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;
    }
    
  • 相关阅读:
    nginx能访问html静态文件但无法访问php文件
    LeetCode "498. Diagonal Traverse"
    LeetCode "Teemo Attacking"
    LeetCode "501. Find Mode in Binary Search Tree"
    LeetCode "483. Smallest Good Base" !!
    LeetCode "467. Unique Substrings in Wraparound String" !!
    LeetCode "437. Path Sum III"
    LeetCode "454. 4Sum II"
    LeetCode "445. Add Two Numbers II"
    LeetCode "486. Predict the Winner" !!
  • 原文地址:https://www.cnblogs.com/lhm-/p/13773921.html
Copyright © 2011-2022 走看看