zoukankan      html  css  js  c++  java
  • 浑水摸鱼

    题目描述

    胖头鱼是一条喜欢摸鱼的鱼。

    他经常去河边摸鱼,每一天,他会选择一段连续的时间去摸鱼,河里有很多不同种类鱼,每一个时间点会有恰好一条鱼出现,而胖头鱼一定能摸到这条鱼(如果他在摸鱼的话)。

    摸完鱼后,他会把摸到的鱼按摸到的时间顺序排成一排,统计今天摸鱼的收益,由于他是个鱼盲,他只能分辨出哪些鱼是同一个种类的,而不会知道一条鱼到底是什么种类的,所以他会把鱼按照种类用正整数标号,同一种鱼用同一个标号,不同的鱼用不同的标号,聪明的胖头鱼会选择字典序最小的标号方法。

    胖头鱼发现在不同的时间摸鱼也可能有相同的收益,两次收益不同当且仅当摸到的鱼的数量不同或者存在某个 $i$ 使得摸到的第 $i$ 条鱼的标号不同。

    胖头鱼可以在任意时间开始摸鱼,任意时间结束摸鱼,但是会至少摸一条鱼。他想让你统计他一共有多少种可能的不同的收益。(他一定只会选择一段连续的时间摸鱼)。

    数据范围

    $1 le a_i le n le 5 imes 10^4$

    题解

    考虑如果我们可以把每个后缀用最小表示出来,然后进行排序,答案为 $frac{n imes (n+1)}{2}-sum lcp(str_i,str_{i+1})$ 。

    考虑把 $hash$ 表示成 $sum (next_i-i) imes p^i$ ,其中 $next_i$ 为和 $i$ 相同的数的下一个位置,如果没有的话就设为 $i$ ,那两个最小表示的串相同的话 $hash$ 就可以体现其相同。

    考虑用主席树维护子串的 $hash$ 值,然后排序时二分 $hash$ (二哈分析)即可。

    效率: $O(nlog^3n)$

    代码

    #include <bits/stdc++.h>
    #define LL long long
    #define U unsigned long long
    using namespace std;
    const int N=5e4+5,M=2e6+5;
    const U B=793999;
    int n,a[N],ls[M],rs[M],T[N],t,p[N],nx[N];
    LL ans; U s[M],b[N]; set<int>S[N];
    #define mid ((l+r)>>1)
    void upd(int &x,int y,int l,int r,int v,U w){
        x=++t;s[x]=s[y]+w;
        ls[x]=ls[y];rs[x]=rs[y];
        if (l==r) return;
        if (mid>=v) upd(ls[x],ls[y],l,mid,v,w);
        else upd(rs[x],rs[y],mid+1,r,v,w);
    }
    U qry(int x,int l,int r,int L,int R){
        if (L<=l && r<=R) return s[x];
        if (mid>=R) return (ls[x]?qry(ls[x],l,mid,L,R):0);
        if (mid<L) return (rs[x]?qry(rs[x],mid+1,r,L,R):0);
        return (ls[x]?qry(ls[x],l,mid,L,R):0)+(rs[x]?qry(rs[x],mid+1,r,L,R):0);
    }
    U hs(int l,int r){return (T[l]?qry(T[l],1,n,l,r):0);}
    int lcp(int x,int y){
        int l=0,r=n-max(x,y)+1;
        while(l<r){
            int i=(l+r+1)>>1;
            if (hs(x,x+i-1)*b[x]==hs(y,y+i-1)*b[y]) l=i;
            else r=i-1;
        }
        return l;
    }
    int Pos(int x,int i){
        return (*S[a[i]].lower_bound(x))-x;
    }
    bool cmp(int x,int y){
        int l=lcp(x,y);
        if (x+l>n) return 1;if (y+l>n) return 0;
        return Pos(x,x+l)<Pos(y,y+l);
    }
    int main(){
        cin>>n;b[0]=1;
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]),b[i]=b[i-1]*B,
            p[i]=i,S[a[i]].insert(i);
        for (int i=n;i;i--){
            T[i]=T[i+1];
            if (nx[a[i]]) upd(T[i],T[i],1,n,
                nx[a[i]],b[n-i+1]*(nx[a[i]]-i));
            nx[a[i]]=i;
        }
        stable_sort(p+1,p+n+1,cmp);ans=1ll*n*(n+1)/2;
        for (int i=1;i<n;i++) ans-=lcp(p[i],p[i+1]);
        printf("%lld
    ",ans);return 0;
    }
  • 相关阅读:
    二、策略模式之商场促销计价器
    一、简单工厂模式之简易计算器
    java学习基础知识十——反射
    java学习基础知识九——IO
    java学习基础知识八——泛型
    java学习基础知识七
    java学习基础知识六
    二、机器学习模型评估
    《将博客搬至CSDN》
    一、Hadoop课程
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12047248.html
Copyright © 2011-2022 走看看