• BZOJ 4212: 神牛的养成计划


    4212: 神牛的养成计划

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 142  Solved: 30
    [Submit][Status][Discuss]

    Description

    Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望......
     
    后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛hzwer很生气,但他知道基因突变的低频性,说不定还有以下优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面你懂的......
     
    黄学长现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串。一个优秀的基因是两个字符串s1和s2,当且仅当s1是某序列的前缀的同时,s2是这个序列的后缀时,hzwer认为这个序列拥有这个优秀基因。
     
    现在黄学长知道了M个优秀基因s1和s2,它们想知道对于给定的优秀基因,有多少个细胞的DNA序列拥有它。
     

    Input

    第一行:N,表示序列数
    接下来N行,每行一个字符串,代表N个DNA序列,它们的总长为L1
    接下来一个M,表示询问数
    接下来M行,每行两个字符串s1和s2,由一个空格隔开,hzwer希望你能在线回答询问,所以s1等于“s1”的所有字符按字母表的顺序向后移动ans位(字母表是一个环),ans为上一个询问的答案,s2同理。例如ans=2  “s1”=qz
    则s1=sb。对于第一个询问,ans=0
    s1和s2的总长度为L2
     

    Output

    输出M行,每行一个数,第i行的数表示有多少个序列拥有第i个优秀基因。
     

    Sample Input

    10
    emikuqihgokuhsywlmqemihhpgijkxdukjfmlqlwrpzgwrwozkmlixyxniutssasrriafu
    emikuqihgokuookbqaaoyiorpfdetaeduogebnolonaoehthfaypbeiutssasrriafu
    emikuqihgokuorocifwwymkcyqevdtglszfzgycbgnpomvlzppwrigowekufjwiiaxniutssasrriafu
    emikuqihgokuorociysgfkzpgnotajcfjctjqgjeeiheqrepbpakmlixyxniutssasrriafu
    emikuqihgokuorociysgfrhulymdxsqirjrfbngwszuyibuixyxniutssasrriafu
    emikuqihgokuorguowwiozcgjetmyokqdrqxzigohiutssasrriafu
    emikuqihgokuorociysgsczejjmlbwhandxqwknutzgdmxtiutssasrriafu
    emikuqihgokuorociysgvzfcdxdiwdztolopdnboxfvqzfzxtpecxcbrklvtyxniutssasrriafu
    emikuqihgokuorocsbtlyuosppxuzkjafbhsayenxsdmkmlixyxniutssasrriafu
    emikuqihgokuorociysgfjvaikktsixmhaasbvnsvmkntgmoygfxypktjxjdkliixyxniutssasrriafu
    10
    emikuqihgokuorociysg yxniutssasrriafu
    aiegqmedckgqknky eqpoowonnewbq
    xfbdnjbazhdnhkhvb qrqgbnmlltlkkbtyn
    bjfhrnfedlhrlolzfv qppxpoofxcr
    zhdfpldcbjf stsidponnvnmmdvap
    zhdfpldcbjfpjmjxdt gdstsidponnvnmmdvap
    dlhjtphgfnjtnqnbhxr wxwmhtsrrzrqqhzet
    bjfhrnfedlhrlolzfv frqppxpoofxcr
    zhdfpldcbjf dponnvnmmdvap
    ucyakgyxweakehes nondykjiiqihhyqvk

    Sample Output

    4
    7
    3
    5
    5
    1
    3
    5
    10
    4

    HINT

    N<=2000

    L1<=2000000

    M<=100000

    L2<=2000000

    Source

     
    [Submit][Status][Discuss]

    万古神牛黄学长 Orz

    又是一道可持久化Trie好题。

    先想暴力,每次先找出有所能匹配上前缀的串,然后在看看这些串里有多少个还能匹配上后缀,这些串的个数就是最终答案。

    然后发现,每次靠前缀筛出来的所有串一定具有一段相同的前缀,这个有点像后缀数组的那种感觉,就是先对所有串按照前缀排序,不难看出每次找出的前缀合法的串一定排成一个区间,我们想访问这个区间的所有串的逆序Trie,这个就是可持久化Trie树了。

    从DaD3zZ那里看到这道题的,他说感觉对串按照前缀排序时使用了C++的Sort函数,逐位比较两个串的大小貌似比较暴力;但是不难想到,我们先建出正序的Trie后,在Trie上按顺序(a->z)DFS出来的就是按前缀排好序的了,这样复杂度就是完美的$O(sum{Length})$,轻松过掉2000000。貌似出题人比较友好(可能就是比较懒),出的数据有点水……

    代码没有,懒得写了…… 懒癌晚期


    UPDATE 写了一发代码,然后图省事用的string,然后cin就给RE了,下午发现问题改成scanf就可以了。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 const int mxn = 2005;
      6 const int mxm = 2100005;
      7 
      8 inline void scan(string &s)
      9 {
     10     s.clear();
     11     
     12     static char buf[mxm];
     13     
     14     scanf("%s", buf);
     15     
     16     for (char *c = buf; *c; ++c)
     17         s.push_back(*c);
     18 }
     19 
     20 int n, m;
     21 
     22 int ord[mxn];
     23 
     24 string str[mxn];
     25 
     26 int end[mxm];
     27 int son[mxm][26];
     28 
     29 int mini[mxm];
     30 int maxi[mxm];
     31 
     32 inline void insert(string &s, int id) {
     33     static int tot = 1;
     34     
     35     int p = 1, len = s.length();
     36     
     37     for (int i = 0; i < len; ++i) {
     38         if (son[p][s[i] - 'a'] == 0)
     39             son[p][s[i] - 'a'] = ++tot;
     40         
     41         p = son[p][s[i] - 'a'];
     42     }
     43     
     44     end[p] = id;
     45 }
     46 
     47 void getOrder(int p) {
     48     static int cnt;
     49     
     50     mini[p] = cnt;
     51     
     52     if (end[p])
     53         ord[++cnt] = end[p];
     54     
     55     for (int i = 0; i < 26; ++i)
     56         if (son[p][i])getOrder(son[p][i]);
     57     
     58     maxi[p] = cnt;
     59 }
     60 
     61 int root[mxn];
     62 
     63 int sum[mxm];
     64 int nxt[mxm][26];
     65 
     66 void insert(int &t, int p, string &s, int d) {
     67     static int tot = 1;
     68     
     69     t = ++tot;
     70     
     71     sum[t] = sum[p] + 1;
     72     
     73     memcpy(nxt[t], nxt[p], sizeof(nxt[t]));
     74     
     75     if (d < s.length())
     76         insert(nxt[t][s[d] - 'a'], nxt[p][s[d] - 'a'], s, d + 1);
     77 }
     78 
     79 inline void trie1(string &s, int &lt, int &rt, int ans) {
     80     int p = 1, len = s.length();
     81     
     82     for (int i = 0; i < len; ++i)
     83         s[i] = (s[i] - 'a' + ans) % 26 + 'a';
     84         
     85     lt = rt = 0;
     86     
     87     for (int i = 0; i < len; ++i) 
     88         p = son[p][s[i] - 'a'];
     89     
     90     lt = mini[p];
     91     rt = maxi[p];
     92 }
     93 
     94 inline void trie2(string &s, int lt, int rt, int &ans) {
     95     int len = s.length();
     96     
     97     reverse(s.begin(), s.end());
     98     
     99     for (int i = 0; i < len; ++i)
    100         s[i] = (s[i] - 'a' + ans) % 26 + 'a';
    101     
    102     int a = root[lt], b = root[rt];
    103     
    104     for (int i = 0; i < len; ++i) {
    105         a = nxt[a][s[i] - 'a'];
    106         b = nxt[b][s[i] - 'a'];
    107     }
    108     
    109     ans = sum[b] - sum[a];
    110 }
    111 
    112 signed main(void) {
    113 #ifndef ONLINE_JUDGE
    114     freopen("in", "r", stdin);
    115     freopen("out", "w", stdout);
    116 #endif
    117 
    118     scanf("%d", &n);
    119     
    120     for (int i = 1; i <= n; ++i)
    121         scan(str[i]);
    122     
    123     for (int i = 1; i <= n; ++i)
    124         insert(str[i], i);
    125     
    126     getOrder(1);
    127     
    128     for (int i = 1; i <= n; ++i)
    129         reverse(str[i].begin(), str[i].end());
    130     
    131     for (int i = 1; i <= n; ++i)
    132         insert(root[i], root[i - 1], str[ord[i]], 0);
    133         
    134     scanf("%d", &m);
    135     
    136     for (int i = 1, lt, rt, ans = 0; i <= m; ++i) {
    137         static string s1, s2;
    138         
    139         scan(s1);
    140         scan(s2);
    141         
    142         trie1(s1, lt, rt, ans);
    143         trie2(s2, lt, rt, ans);
    144         
    145         printf("%d
    ", ans);
    146     }
    147 }

    @Author: YouSiki

  • 相关阅读:
    互联网与局域网(四)
    Socket介绍(五)
    HttpClient(七)
    TCP协议与HTTP协议区别
    TCP连接的三次握手
    context-param和init-param区别
    【HPU】[1736]老王修马路(二)
    【HPU】[1735]老王修马路(一)
    【HPU】[1734]老王修公园
    【HPU】[1733]神奇的数字9
  • 原文地址:https://www.cnblogs.com/yousiki/p/6550484.html
Copyright © 2020-2023  润新知