zoukankan      html  css  js  c++  java
  • 【bzoj4698】[Sdoi2008] Sandy的卡片 后缀数组

    题目描述

    Sandy和Sue的热衷于收集干脆面中的卡片。然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型。每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。Sandy的卡片数远远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到哪个等级的人物模型。

    输入

    第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数
    第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中的第j个数
    n<=1000,M<=1000,2<=Mi<=101

    输出

    一个数k,表示可以获得的最高等级。

    样例输入

    2
    2 1 2
    3 4 5 9

    样例输出

    2


    题解

    后缀数组

    由于每组数共同加上一个数,它们的差值不变,所以可以把每组数作差,保存到r中。

    然后就是求n个字符串的最长公共字串。

    把这些串依次连接起来,放到同一个字符串中,中间用从未出现过的数字隔开(这里使用1000)

    然后倍增求出height。

    二分答案,若答案合法,则一定有连续的height>mid,且它们属于不同的字符串。

    据此写出judge函数,这里我用到了一个栈,均摊时间复杂度为O(n)。

    求的是差值,问的是个数,答案别忘了+1。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 1000005
    using namespace std;
    int ws[N] , wv[N] , wa[N] , wb[N] , sa[N] , r[N] , rank[N] , height[N] , bl[N] , n , a[N] , m , vis[N] , k , sta[N] , top;
    char str[N];
    void da()
    {
        int i , j , p , *x = wa , *y = wb , *t;
        for(i = 0 ; i < m ; i ++ ) ws[i] = 0;
        for(i = 0 ; i < n ; i ++ ) ws[x[i] = r[i]] ++ ;
        for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
        for(i = n - 1 ; i >= 0 ; i -- ) sa[--ws[x[i]]] = i;
        for(p = j = 1 ; p < n ; j <<= 1 , m = p)
        {
            for(p = 0 , i = n - j ; i < n ; i ++ ) y[p ++ ] = i;
            for(i = 0 ; i < n ; i ++ ) if(sa[i] - j >= 0) y[p ++ ] = sa[i] - j;
            for(i = 0 ; i < n ; i ++ ) wv[i] = x[y[i]];
            for(i = 0 ; i < m ; i ++ ) ws[i] = 0;
            for(i = 0 ; i < n ; i ++ ) ws[wv[i]] ++ ;
            for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
            for(i = n - 1 ; i >= 0 ; i -- ) sa[--ws[wv[i]]] = y[i];
            for(t = x , x = y , y = t , x[sa[0]] = 0 , p = i = 1 ; i < n ; i ++ )
            {
                if(y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j])
                    x[sa[i]] = p - 1;
                else
                    x[sa[i]] = p ++ ;
            }
        }
        for(i = 1 ; i < n ; i ++ ) rank[sa[i]] = i;
        for(p = i = 0 ; i < n - 1 ; height[rank[i ++ ]] = p)
            for(p ? p -- : 0 , j = sa[rank[i] - 1] ; r[i + p] == r[j + p] ; p ++ );
    }
    bool judge(int mid)
    {
        int i , num = 0;
        for(i = 0 ; i < k ; i ++ ) vis[i] = 0;
        top = 0;
        for(i = 2 ; i <= n - 1 ; i ++ )
        {
            if(height[i] >= mid)
            {
                if(!vis[bl[sa[i - 1]]]) vis[bl[sa[i - 1]]] = 1 , num ++ , sta[++top] = bl[sa[i - 1]];
                if(!vis[bl[sa[i]]]) vis[bl[sa[i]]] = 1 , num ++ , sta[++top] = bl[sa[i]];
                if(num == k) return 1;
            }
            else if(num > 0)
            {
                num = 0;
                while(top) vis[sta[top -- ]] = 0;
            }
        }
        return 0;
    }
    int main()
    {
        int i , j , p , le = 0 , ri = 0x7fffff , mi , ans = 0 , minn = 0x7fffffff;
        scanf("%d" , &k);
        for(i = 0 ; i < k ; i ++ )
        {
            scanf("%d" , &p);
            ri = min(ri , p - 1);
            for(j = 0 ; j < p ; j ++ )
                scanf("%d" , &a[j]);
            for(j = 0 ; j < p - 1 ; j ++ )
            {
                bl[n] = i;
                r[n] = a[j + 1] - a[j];
                minn = min(minn , r[n ++ ]);
            }
            r[n ++ ] = 1000;
        }
        for(i = 0 ; i < n ; i ++ ) r[i] -= minn - 1 , m = max(m , r[i] + 1);
        n ++ ;
        da();
        while(le <= ri)
        {
            mi = (le + ri) >> 1;
            if(judge(mi))
            {
                ans = mi;
                le = mi + 1;
            }
            else
            {
                ri = mi - 1;
            }
        }
        printf("%d
    " , ans + 1);
        return 0;
    }
  • 相关阅读:
    css backgroud属性与雪碧技术
    css margin 外边距塌陷问题
    css 浮动元素与清除浮动
    css 盒模型的概念与使用
    七年iOS架构师教你如何一举拿下35K的Offer,(附面试技巧)
    iOS开发者月薪想要突破30K,需要经历+提升些什么?
    月薪 8K 与30K的程序员 区别到底在哪里?
    那些月薪35K以上的iOS开发者 都掌握了什么技能?
    从事 iOS 开发8年的面经——送给准备跳槽的你!
    想进BAT大厂的 iOS程序员,看完这个你还觉得Offer难拿吗???
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6272954.html
Copyright © 2011-2022 走看看