• dtoi4670 浑水摸鱼


    题意:

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

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

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

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

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

    题解:

         本题其实就是求另类的本质不同的子串个数。

         考虑如果是一般的本质不同怎么做呢,弄一个后缀数组,然后height之和就是重复的个数。

         这题其实也差不多,只不过排序的cmp有点复杂。

         如果我们要比较两个后缀,那么我们先分别暴力将它搞成字典序最小的标号方法,然后直接比较,接下来操作就和上面说的一样。只不过这个做法肯定是会超时的。我们要解决的问题就是如何快速比较后缀,如果我们将hash表示成$sum (next_i-i) imes p^i$,我们发现,hash值相同的就是同构的。

         那么如何维护这个hash值,使用可持久化线段树维护,这样我们就得到了一个快速判断是否同构的方法。

         接下来我们在排序的时候进行二分hash比较大小,即可在$O(nlog^3n)$的时间复杂度内解决问题。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int INF=131333131;
    int n,a[50002],head[50002],las[50002],nex[50002],rt[50002],cnt,t[50002];
    vector<int>g[50002];
    long long ans;
    unsigned int jc[50002],sum;
    typedef struct{
        unsigned int sum;
        int ls,rs;
    }P;
    P p[30000002];
    void build(int root,int begin,int end){
        if (begin==end)
        {
            p[root].sum=0;
            return;
        }
        int mid=(begin+end)/2;
        p[root].ls=++cnt;p[root].rs=++cnt;
        build(p[root].ls,begin,mid);build(p[root].rs,mid+1,end);
        p[root].sum=p[p[root].ls].sum*jc[end-mid]+p[p[root].rs].sum;
    }
    void gengxin(int root,int las,int begin,int end,int wz,int z){
        if (begin==end)
        {
            p[root].sum=z-begin;
            return;
        }
        int mid=(begin+end)/2;
        if (wz<=mid)
        {
            p[root].rs=p[las].rs;p[root].ls=++cnt;
            gengxin(p[root].ls,p[las].ls,begin,mid,wz,z);
        }
        else
        {
            p[root].ls=p[las].ls;p[root].rs=++cnt;
            gengxin(p[root].rs,p[las].rs,mid+1,end,wz,z);
        }
        p[root].sum=p[p[root].ls].sum*jc[end-mid]+p[p[root].rs].sum;
    }
    void chaxun(int root,int begin,int end,int begin2,int end2){
        if (!root)
        {
            sum*=jc[min(end,end2)-max(begin,begin2)+1];
            return;
        }
        if (begin>=begin2 && end<=end2)
        {
            sum=sum*jc[end-begin+1]+p[root].sum;
            return;
        }
        int mid=(begin+end)/2;
        if (!(mid<begin2 || begin>end2))chaxun(p[root].ls,begin,mid,begin2,end2);
        if (!(end<begin2 || mid+1>end2))chaxun(p[root].rs,mid+1,end,begin2,end2);
    }
    unsigned int cx(int x,int y){
        sum=0;
        chaxun(rt[y],1,n,x,y);
        return sum;
    }
    int ef(int num,int x,int y,int z){
        int mid;
        while(x<y)
        {
            mid=(x+y)/2;
            if (g[num][mid]<z)x=mid+1;else y=mid;
        }
        return g[num][x];
    }
    bool cmp(const int& x,const int& y){
        int lef=0,righ=min(n-x+1,n-y+1),mid;
        while(lef<righ)
        {
            mid=(lef+righ+1)/2;
            if (cx(x,x+mid-1)==cx(y,y+mid-1))lef=mid;
            else righ=mid-1;
        }
        if (lef==min(n-x+1,n-y+1))return (x>y);
        return (ef(a[x+lef],0,g[a[x+lef]].size()-1,x)-x+1<ef(a[y+lef],0,g[a[y+lef]].size()-1,y)-y+1);
    }
    int main()
    {
        scanf("%d",&n);jc[0]=1;ans=(long long)n*(n+1)/2;
        for (int i=1;i<=n;i++)jc[i]=jc[i-1]*INF;
        for (int i=1;i<=n;i++){scanf("%d",&a[i]);g[a[i]].push_back(i);}
        memset(head,-1,sizeof(head));
        for (int i=1;i<=n;i++)
        {
            if (head[a[i]]!=-1)
            {
                las[i]=head[a[i]];nex[head[a[i]]]=i;
            }
            head[a[i]]=i;
        }
        for (int i=1;i<=n;i++)
        {
            rt[i]=++cnt;
            if (!las[i])
            {
                p[rt[i]].ls=p[rt[i-1]].ls;p[rt[i]].rs=p[rt[i-1]].rs;
            }
            else gengxin(rt[i],rt[i-1],1,n,las[i],i);
        }
        for (int i=1;i<=n;i++)t[i]=i;
        stable_sort(t+1,t+n+1,cmp);
        for (int i=2;i<=n;i++)
        {
            int x=t[i-1],y=t[i];
            int lef=0,righ=min(n-x+1,n-y+1),mid;
            while(lef<righ)
            {
                mid=(lef+righ+1)/2;
                if (cx(x,x+mid-1)==cx(y,y+mid-1))lef=mid;
                else righ=mid-1;
            }
            ans-=lef;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    IntelliJ IDEA 2017版 SpringBoot的核心配置详解
    路由追踪程序traceroute/tracert分析与科普
    traceroute追踪路由命令
    ping 命令
    hostname命令,修改主机名及host文件
    net-tools工具arp命令
    ifup 和 ifdown
    net-tools工具ifconfig 命令
    iproute2 对决 net-tools
    什么是带内管理 带外管理
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12329413.html
Copyright © 2020-2023  润新知