zoukankan      html  css  js  c++  java
  • bzoj 4104 [Thu Summer Camp 2015]解密运算——思路

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4104

    想了很久,想出一个 nlogn (也许是 n2logn )的,可惜空间是 n2

    已知字符集,对它排个序,对应上给出的那些字符,就能知道每个字符前面是哪个字符。

    这样得到了一些长度为2的串。这些长度为2的串一定也是这 n+1 行的开头;所以对它们排序后对应上给出的那些字符,就能得到长度为3的串。这样就能得到答案。

    但是太慢。考虑已知长度为 k 的串,想一下把它接成 2*k 的串。

    发现如果已经接好了,则对 2*k 的串排序,它们的前 k 个字符的顺序就和现在看见的长度为 k 的串的顺序一样。

    所以对现在的长度为 k 的串排序,并再保留排序前的样子,然后考虑排序后的每个串接到排序前的哪个串上。

    发现对长度为 2*k 的串排序就是以长度为 k 时排序前的串为第一关键字、长度为 k 的排序后的串为第二关键字的。

    所以将长度为 k 的串排序后,已知每个串的上一个字符是什么;从前到后枚举排序后的长度为 k 的串,找到以该串对应字符结尾的那些串,在这个类别里找到第一个还没被接上的串,把自己接到该串后面。

    这样一共 logn 层,每层大概是 O(n) ?不过还没想好怎么实现“接上去”,也许每层要变成 n2 了。

    然后看了题解。

    已知字符集和每个字符后面接着的那个串的字典序。

    所以可以得到后面的那个串前面接上该字符后的新串的字典序。(形如“一个字符+一个串",并且已知“一个串”的不算那个字符时的字典序排名)

    同时由给出的那些字符,把新串按字典序对应上,就能知道每个新串的上一个字符是什么。

    “上一个字符+一个串”的样子就是一个新串的样子。所以知道这个新串对应的上一个字符,可以尝试直接找这个新串对应的新串。如果能找到的话,得到新的自身排名和上一个字符,就能顺着把原来新串的从最后一个位置开始的每一个“上一个字符”找出来,即找到了原串。

    其实问题就在于如果有很多个“同一个字符+一个串”,不知道自己这个串应该接在其中的哪个后面。

    但已经知道这些备选方案接着的那个串的字典序排名了;而且也知道自己这个串的字典序排名。所以按排名对应上就行啦!对应上之后又知道了自己串的新的排名和上一个字符,就能做下去了。

    自己的思路要维护 n+1 个串,而且每次要排序。没有利用上“前续了一个字符后新串的排名已知”这个条件。

    因为每次要前续一个字符,所以把给出的条件从“已知每个排名对应的上一个字符”转为“已知每个字符后面串的排名”,就能实现一直做下去。

    看到后缀数组,自己总想着分析它的倍增,而最近这两道题都是从它的“后缀去掉开头字符后仍是一个已知后缀”的角度考虑。学习一下这个思路。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=2e5+5;
    int n,m,dy[N],prn[N];
    struct Node{int a,b;}t[N];
    bool operator< (Node u,Node v){return u.a<v.a||(u.a==v.a&&u.b<v.b);}
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int main()
    {
      n=rdn();m=rdn();
      for(int i=1,d;i<=n+1;i++)
        {
          t[i].a=rdn(); t[i].b=i;
        }
      sort(t+1,t+n+2);
      for(int i=1;i<=n+1;i++)dy[t[i].b]=i;
      int cr=1,bj=n;
      while(bj)
        {
          cr=dy[cr];prn[bj--]=t[cr].a;
        }
      for(int i=1;i<=n;i++)printf("%d ",prn[i]);puts("");
      return 0;
    }
  • 相关阅读:
    P5107 能量采集
    P4655 [CEOI2017]Building Bridges
    P1129 [ZJOI2007]矩阵游戏
    P5299 [PKUWC2018]Slay the Spire
    P1625求和 giao精大杂烩
    背包
    根号分治
    CF963B
    国王游戏
    P6006 USACO 3SUM G
  • 原文地址:https://www.cnblogs.com/Narh/p/10081285.html
Copyright © 2011-2022 走看看