• bzoj 4104 解密运算 —— 思路


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

    一开始发现了给出的顺序是按这些末尾字符后面的后缀排序得到的;

    然后发现可以一个一个把字符串补全;

    因为首先知道所有单个字符,排序后就是那些串的第一位,和末尾连起来,得到 n+1 个二元组;

    然后把这 n+1 个二元组排序,再和末尾连起来,得到 n+1 个三元组;

    以此类推,最后可以得到整个串,可惜这样做是 n^2 的,空间也是;

    考虑倍增?因为这样得到的四元组的前两个位置其实和当初得到的二元组一样...

    而且这个过程和后缀数组的排序也很像啊!二元组是第二关键字,再加一个二元组是第一关键字...

    然后想了一晚上也没想明白怎么倍增;

    实际上,我又忘了后缀排序的另一种方法——(首字符相同的)去掉首字符,看后面后缀的排序;

    这道题——给出的末尾字符是首字符的话,那么它们已经按去掉首字符的后缀后排好序了;

    所以把每行的字符以字符大小为第一关键字,行数为第二关键字排序,就知道在原串中这些首字符对应的后缀的排名了;

    而这些行也是按字典序排序的;

    所以知道了每一行末尾字符是哪一行的开头;

    于是从 “.” 开始,按排名对应回每一行,就倒着得到了原串!

    在我原来的想法中,问题在于相同的字符作为开头,无法知道谁对应哪个末尾;

    而如果利用行的排名,相同字符之间的排名也明确了,就不需要每次再排序来确定对应的末尾字符;

    后缀排序的那个方法(去掉首字符)...真常用啊...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=2e5+5;
    int n,m,rk[xn],s[xn],ans[xn];
    struct N{int s,id;}p[xn];
    bool cmp(N x,N y){return x.s<y.s||(x.s==y.s&&x.id<y.id);}
    bool cmp2(N x,N y){return x.id<y.id;}
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n+1;i++)
        scanf("%d",&s[i]),p[i].s=s[i],p[i].id=i;
      sort(p+1,p+n+2,cmp);
      for(int i=1;i<=n+1;i++)rk[p[i].id]=i;
      int top=0,nw=p[1].id;
      while(top<n+1)ans[++top]=s[nw],nw=rk[nw];
      while(top>1)printf("%d ",ans[top--]); puts("");
      return 0;
    }
  • 相关阅读:
    创建FLASK,同步docker
    FLASK Buleprint
    restful api
    Angular JS
    线程日志
    将项目部署到linux下的docker容器中
    安装和卸载docker
    学习目录总编
    Ansible
    装饰器
  • 原文地址:https://www.cnblogs.com/Zinn/p/10081009.html
Copyright © 2020-2023  润新知