zoukankan      html  css  js  c++  java
  • 【BZOJ】【3439】Kpm的MC密码

    Trie树/可持久化线段树


      神题啊……搞了我一下午= =(其实第233个提交也是我的)

      我一开始的思路:这个找kpm串的过程,其实就跟在AC自动机上沿fail倒着往下走是差不多的(看当前是哪些点的后缀,如果某个串的后缀是当前串,那它的fail就会指向这里)所以就在fail树上bfs一遍,然后找到所有的编号,排序后输出第k小……

      然后顺利地WA了 QAQ

      只好取膜拜题解……哦原来只要把每个串倒过来,建Trie树的时候,就相当于找当前这个串的子树!

      在子树中统计啊……so easy啦~dfs一遍,把儿子中的编号传给父亲啦~然后就会发现光荣TLE了>_>

      shen me gui!为什么呢?很简单啦,结点那么多,最坏情况下要把n个编号上传n次(比如有10W个相同的串,每个串都为 "aaa....aa"(10W个a))妥妥的TLE了。

      等等……刚刚好像说是子树查询第K大?dfs序不是很好吗!瞬间转成求区间第K大!可持久化线段树!

      ok,终于顺利AC……

      1 /**************************************************************
      2     Problem: 3439
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:1240 ms
      7     Memory:51688 kb
      8 ****************************************************************/
      9  
     10 //BZOJ 3439
     11 #include<vector>
     12 #include<cstdio>
     13 #include<cstring>
     14 #include<cstdlib>
     15 #include<iostream>
     16 #include<algorithm>
     17 #define rep(i,n) for(int i=0;i<n;++i)
     18 #define F(i,j,n) for(int i=j;i<=n;++i)
     19 #define D(i,j,n) for(int i=j;i>=n;--i)
     20 #define pb push_back
     21 using namespace std;
     22 inline int getint(){
     23     int v=0,sign=1; char ch=getchar();
     24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
     25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
     26     return v*sign;
     27 }
     28 const int N=1e5+10,INF=~0u>>2;
     29 typedef long long LL;
     30 /******************tamplate*********************/
     31 struct Trie{
     32     int ch[26],num;
     33     bool sign;
     34 }T[N];
     35 int cnt=0,n,tot,pos[N];
     36 inline int id(char c){return c-'a';}
     37 vector<int>v[N];
     38 void Insert(char *s,int num){
     39     int x=0,y;
     40     D(i,strlen(s)-1,0){
     41         y=id(s[i]);
     42         if (T[x].ch[y]==0)
     43             T[x].ch[y]=++cnt;
     44         x=T[x].ch[y];
     45     }
     46     T[x].sign=1;
     47     v[x].pb(num);
     48     pos[num]=x;
     49 }
     50 int st[N],ed[N],a[N];
     51 void dfs(int x){
     52     st[x]=tot+1;
     53     rep(i,v[x].size()) a[++tot]=v[x][i];
     54     rep(i,26)
     55         if (T[x].ch[i]!=0)
     56             dfs(T[x].ch[i]);
     57     ed[x]=tot;
     58 }
     59 struct Tree{
     60     int cnt,l,r;
     61 }t[N*30];
     62 int root[N],num=0;
     63 #define mid (l+r>>1)
     64 void update(int &o,int l,int r,int pos){
     65     t[++num]=t[o], o=num, ++t[o].cnt;
     66     if (l==r) return;
     67     if (pos<=mid) update(t[o].l,l,mid,pos);
     68     else update(t[o].r,mid+1,r,pos);
     69 }
     70 int query(int i,int j,int rank){
     71     i=root[i]; j=root[j];
     72     int l=1,r=n;
     73     while(l!=r){
     74         if (t[t[j].l].cnt-t[t[i].l].cnt>=rank)
     75             r=mid,i=t[i].l,j=t[j].l;
     76         else{
     77             rank-=t[t[j].l].cnt-t[t[i].l].cnt;
     78             l=mid+1,i=t[i].r,j=t[j].r;
     79         }
     80     }
     81     if (t[j].cnt-t[i].cnt<rank) return -1;
     82     return l;
     83 }
     84 #undef mid
     85 char s[N];
     86 int main(){
     87 #ifndef ONLINE_JUDGE
     88     freopen("3439.in","r",stdin);
     89     freopen("3439.out","w",stdout);
     90 #endif
     91     n=getint();
     92     F(i,1,n){
     93         scanf("%s",s);
     94         Insert(s,i);
     95     }
     96     dfs(0);
     97 #ifdef debug
     98     F(i,1,tot) printf("%d ",a[i]);puts("");
     99     F(i,1,n) printf("%d %d
    ",st[pos[i]],ed[pos[i]]);
    100 #endif
    101     F(i,1,tot){
    102         root[i]=root[i-1];
    103         update(root[i],1,n,a[i]);
    104     }
    105 #ifdef debug
    106     F(i,1,num) printf("%d %d %d %d
    ",i,t[i].l,t[i].r,t[i].cnt);
    107 #endif
    108     int k;
    109     F(i,1,n){
    110         k=getint();
    111         int ans=query(st[pos[i]]-1,ed[pos[i]],k);
    112 //      printf("%d
    ",ans>n ? -1 : ans);
    113         printf("%d
    ",ans);
    114     }
    115     return 0;
    116 }
    View Code

    3439: Kpm的MC密码

    Time Limit: 15 Sec  Memory Limit: 256 MB
    Submit: 234  Solved: 113
    [Submit][Status][Discuss]

    Description


     背景

        想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的。。。),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身份验证问题了。。。

     描述

        Kpm当年设下的问题是这样的:

        现在定义这么一个概念,如果字符串s是字符串c的一个后缀,那么我们称c是s的一个kpm串。

        系统将随机生成n个由a…z组成的字符串,由1…n编号(s1,s2…,sn),然后将它们按序告诉你,接下来会给你n个数字,分别为k1…kn,对于每 一个ki,要求你求出列出的n个字符串中所有是si的kpm串的字符串的编号中第ki小的数,如果不存在第ki小的数,则用-1代替。(比如说给出的字符 串是cd,abcd,bcd,此时k1=2,那么”cd”的kpm串有”cd”,”abcd”,”bcd”,编号分别为1,2,3其中第2小的编号就是 2)(PS:如果你能在相当快的时间里回答完所有n个ki的查询,那么你就可以成功帮kpm进入MC啦~~)

    Input

        第一行一个整数 n 表示字符串的数目

        接下来第二行到n+1行总共n行,每行包括一个字符串,第i+1行的字符串表示编号为i的字符串

        接下来包括n行,每行包括一个整数ki,意义如上题所示

     

    Output

        包括n行,第i行包括一个整数,表示所有是si的kpm串的字符串的编号中第ki小的数

     

    Sample Input


    3
    cd
    abcd
    bcd
    2
    3
    1

    Sample Output

    2
    -1
    2

    样例解释

    “cd”的kpm 串有”cd”,”abcd”,”bcd”,编号为1,2,3,第2小的编号是

    2,”abcd”的kpm串只有一个,所以第3小的编号不存在,”bcd”的kpm

    串有”abcd”,”bcd”,第1小的编号就是2。

    数据范围与约定

    设所有字符串的总长度为len


    对于100%的数据,1<=n<=100000,0

    HINT

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    Introduction to Mathematical Thinking
    学习 Unix 常用命令
    学习 《UNIX网络编程》
    学习编译并运行C代码
    Introduction to Mathematical Thinking
    Introduction to Mathematical Thinking
    CentOS 6和CentOS 7防火墙的关闭
    centOS 7下无法启动网络(service network start)错误解决办法(应该是最全的了。。。)
    虚拟机中的CentOS 7设置固定IP连接最理想的配置
    使用VMware安装CentOS7详请
  • 原文地址:https://www.cnblogs.com/Tunix/p/4394778.html
Copyright © 2011-2022 走看看