zoukankan      html  css  js  c++  java
  • bzoj2309 CTSC2011 字符串重排

    题意:

    给定n个字符串S1,S2,S3,...,Sn,把它们排序

    设排序结果为Sp1,Sp2,Sp3,...,Spn

    现在给定q个任务,每个任务的格式都是"要求在排序结果中Sa恰好在Sb前一个"

    你排出的串满足第i个任务,就可以得到2^i(2的i次方)的奖励

    现在有两个问题:

    1.求相邻两项LCP平方和W的最大值

    2.求出当W最大时能获得最多奖励的排序结果

    数据&部分分:

    对于 10%的数据,n ≤ 10,q = 1, 每个字符串的长度不超过 50; 
    对于 20%的数据,n ≤ 50,q = 1, 每个字符串的长度不超过 50; 
    对于 50%的数据,n ≤ 1000,q ≤ 1000, 每个字符串的长度不超过 1000; 
    对于 70%的数据,任意字符串不为其他任何一个字符串的前缀; 
    对于100%的数据, n ≤ 40 000, q ≤ 100 000, 每个字符串的长度不超过10 000; 
    对于 100%的数据,所有字符串的长度和不超过 200000。

    bzoj坑爹啊,没有数据范围,还好Codevs上有

    思路:

    嗯,WJMZBMR远古巨神的神题,肯定不是我等一般人能做出来的
    当然,在我有理有据的乱搞之前,我们先要确定这道题考的是啥
    多个串,很像AC自动机,但LCP又跟AC自动机联系不起来,
    苦苦思索2晚上无果后我的思路到了关键的一点:陈立杰在2012年的《后缀自动机讲稿》上有这么一句话

    然后我就确定了:不会有后缀数据结构,毕竟CTSC也不太可能会出后缀数组
    好,那么字符串还剩下什么数据结构呢
    我们看数据范围的最后一条
    答案脱口而出:Trie树!
    对,就是Trie树大暴力

    整理一下思路:我们明确两个大方向
    (1)根据历史的进程,这道题一定是Trie树
    (2)Trie树上的LCP,其实就是LCA的深度

    好,现在我们开始做题
    我们写一个动态Trie动态维护排序信息

    别急,先打打暴力,看看有没有什么特殊性质
    于是我在数学课上手算了4组数据发现
    第一问是tm逗你玩的,W最大的情况是"字典序"
    本来想着dp的我抱头痛哭

    严谨证明的话...不太会

    可能是在Trie树上搞个路径统计?

    可以知道的是:一个字符串排列就相当于Trie树上一条从根出发回到根的路径

    不知道,反正这一问在Trie树上按字典序dfs一下就好了

    我们看第二问
    第二问会发现,越往后奖励越多,所以我们考虑操作离线倒序,如果当前任务可以取就取到,然后更改Trie树上的路径(我就是在这yy出了LinkCutTrie的)

    于是开始了漫长的手推

    草稿纸都用了一张多,最后发现可以弄一个Trie链剖分+树套树

    看了看前人的代码长度大概都是这么做的吧

    然后在纸上写了很多乱七八糟的东西

    ...要滚去写作业了,幸运的是找到了曾经的题解

    也算是看了一点点吧

    毕竟还是个没学上的蒟蒻不可能一下子A掉CTSC的是不是?

    放个链接吧

    https://wenku.baidu.com/view/d6e7e02b647d27284b73516a.html?from=search

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define ll long long
    using namespace std;
    const int maxn=40010;
    const int maxq=100010;
    int n,q,dfn;
    int x[maxq],y[maxq];
    char SS[maxn];
    struct Trie
    {
        Trie *ch[27];
        int Size,dep,rnk;
        Trie *prev,*next;
        Trie *first,*last;
        Trie *father,*top;
        Trie()
        {
            memset(ch,0,sizeof(ch));
            Size=0;
            father=0;
            prev=next=first=last=0;
        }
        Trie *pre()
        {
            Trie *now;
            for(now=this;now->prev;now=now->prev);
            return now;
        }
        Trie *suf() 
        {
            Trie *now;
            for(now=this;now->next;now=now->next);
            return now;
        }
        Trie *insert(int val)
        {
            Trie* &now=ch[val];
            if (now==0)
            {
                now=new Trie;
                now->father=this;
                Size++;
            }
            return now;
        }
        int count() 
        {
            Trie *now=pre();
            int cnt=0;
            while(now) 
            {
                ++cnt;
                now=now->next;
            }
            return cnt;
        }
        bool find(Trie*o) 
        {
            Trie *now=pre();
            while(now) 
            {
                if(now==o)return true;
                now=now->next;
            }
            return false;
        }
        bool canFirst(Trie*c) 
        {
            if (c==first)return true;
            if (first != 0 || c->prev != 0)return false;
            if (c->suf()==last && c->count()!=Size)return false;
            return true;
        }
        bool canLast(Trie*c) 
        {
            if (c == last)return true;
            if (last!=0 || c->next!=0)return false;
            if (c->pre()==first && c->count()!=Size)return false;
            return true;
        }
        bool canNext(Trie*c1,Trie*c2) 
        {
            if (c1->next==c2)return true;
            if (c1->next!=0 || c2->prev!=0)return false;
            if (c1==last || c2==first)return false;
            if (c1->find(c2))return false;
            if (c1->pre()==first && c2->suf()==last && c1->count()+c2->count()<Size)return false;
            return true;
        }
        void dfs(int de) 
        {
            rnk=dfn++;
            dep=de;
            if(father==0) top=0; 
            else if(father->Size>1)top=father;
            else top=father->top;
            for(int i=0;i<27;i++)if(ch[i]!=0)ch[i]->dfs(dep+1);
        }
    };
    int todolis[maxq];
    Trie *es[maxn],*ed[maxn],*rt;
    Trie *getLCA(Trie *a, Trie *b) 
    {
        while("woxihuan_keduoli")
        {
            if(a==b)return a;
            if(a==rt || b==rt)return rt;
            if( (a->top->dep) < (b->top->dep) )swap(a,b);
            a=a->top;
        }
    }
    void set(Trie *a,Trie *b) 
    {
        Trie *l=getLCA(a,b);
        while(a->top!=l) 
        {
            Trie*fa=a->top;
            fa->last=a;
            a=fa;
        }
        while(b->top!=l) 
        {
            Trie*fa=b->top;
            fa->first=b;
            b=fa;
        }
        a->next=b,b->prev=a;
    }
    bool check(Trie *a, Trie *b) 
    {
        Trie *l=getLCA(a, b);
        while(a->top!=l) 
        {
            Trie*fa=a->top;
            if(!fa->canLast(a))return false;
            a=fa;
        }
        while(b->top!=l) 
        {
            Trie*fa=b->top;
            if(!fa->canFirst(b))return false;
            b=fa;
        }
        if(!l->canNext(a,b))return false;
        return true;
    }
    bool cmp(Trie*a, Trie*b){return (a->rnk) < (b->rnk);}
    ll ans,cnt;
    int main()
    {
        scanf("%d%d",&n,&q);
        rt=new Trie;
        for(int i=0;i<n;i++) 
        {
            scanf("%s",SS);
            int len=strlen(SS);
            Trie *temp=rt;
            for(int j=0;j<len;j++)temp=temp->insert(SS[j]-'a'+1);
            temp=temp->insert(0);
            ed[i]=temp;
        }
        ll ans=0;
        rt->dfs(0);
        for(int i=0;i<q;i++) scanf("%d%d",&x[i],&y[i]),--x[i],--y[i];
        for(int i=q-1;i>=0;i--) 
            if(check(ed[x[i]],ed[y[i]])) 
            {
                set(ed[x[i]],ed[y[i]]);++cnt;todolis[i]=1;
            }
        for(int i=0;i<n;i++)es[i]=ed[i];
        sort(es,es+n,cmp);
        ll tmp;
        for(int i=0;i<n-1;i++)
        {
            tmp=getLCA(es[i],es[i+1])->dep;
            ans+=tmp*tmp;
        }
        printf("%lld
    %lld
    ",ans,cnt);
        for(int i=0;i<q;i++)if(todolis[i])printf("%d ",i+1);
        return 0;
    }
    View Code

    OI加油 期末加油

  • 相关阅读:
    处理不均衡数据 (Imbalanced data)
    过拟合 (Overfitting)
    加速神经网络训练 (Speed Up Training)
    Python3 S.join() 个人笔记
    OpenCV中的图像形态学转换
    OpenCV中的绘图函数
    OpenCV中图像的BGR格式及Img对象的属性说明
    OpenCV中图像的读取,显示与保存
    msyql-02
    jumpserver的快速部署
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/8270838.html
Copyright © 2011-2022 走看看