zoukankan      html  css  js  c++  java
  • G 唐纳德与子串(easy)(华师网络赛---字符串,后缀数组)(丧心病狂的用后缀自动机A了一发Easy)

    Time limit per test: 1.0 seconds

    Memory limit: 256 megabytes

    子串的定义是在一个字符串中连续出现的一段字符。这里,我们使用 s[lr] 来表示 s 字符串从 l 到 r(闭区间)的子串。在本题中,字符串下标从 0 开始。显然,对于长度为 n 的字符串共有 n(n+1)2 个子串。

    对于一个给定的字符串 s,唐纳德给出 q 次询问,第 i 次询问包括三个参数 li,ri,zi,问在 s[liri] 的所有子串中共有多少个恰好为 zi

    Input

    输入具有如下形式:

    sql1 r1 z1l2 r2 z2lq rq zq

    第一行一个字符串 s

    第二行一个整数 q

    接下来每行:首先两个整数 li,ri (0liri<|s|),然后是一个非空字符串 zi。整数和整数,整数和字符串间以单空格隔开。

    字符串中只会出现 26 个小写英文字母。

    数据规模约定:

    • 对于 Easy 档:1|s|100,q|zi|100
    • 对于 Hard 档:1|s|105,q|zi|105

    Output

    对于每次询问,输出一个整数,表示答案。

    Examples

    input

    thisisagarbagecompetitionhahaha
    5
    0 30 a
    1 5 is
    25 30 hah
    6 12 ag
    7 12 ag
    

    output

    6
    2
    2
    2
    1

    题意:

    给定一个模板串X,求每次给出的匹配串在模板串x特定的位置[L,R]区间出现次数。

    自己思路:

    小数据,KMP水过。对于大数据,emmmm,感觉后缀自动机没想出来,就没想了,GG。

    官方题解:

    “考虑离线处理。将所有查询和母串相连建后缀数组。对于每一个查询,在排好序的后缀数组中恰好有一段相对应,可以二分求得 L,R。问题就转换为在 L,R 区间内有多少后缀的下标在查询区间范围内的。这是一个非常经典的区间问题。继续考虑离线处理,从大往小将数插入,然后使用树状数组轻松解决。时间复杂度 O(nlogn)

    事实上本题的做法非常套路,所以过得人也比 F 多(???)。

    据验题人说暴力加疯狂特判也能过,而且玄学优化不可卡。暴力姿势太大,比不来。”

    Easy部分:KMP暴力

    小数据
    #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<memory.h> using namespace std; char a[1000010],b[1000010]; int Next[1000010],L1,L2,ans,x,y; void _next() { int i,k; Next[1]=0; for(i=2,k=0;i<=L2;i++){ while(k&&b[k+1]!=b[i]) k=Next[k]; if(b[k+1]==b[i]) k++; Next[i]=k; } } void _kmp() { _next(); int i,k; ans=0; for(i=x,k=0;i<=y;i++){ while(k&&b[k+1]!=a[i]) k=Next[k]; if(b[k+1]==a[i]) k++; if(k==L2&&i-L2+1>=x) { ans++; k=Next[k]; } } } int main() { int q; scanf("%s",a+1); scanf("%d",&q); L1=strlen(a+1); while(q--){ ans=0; scanf("%d%d",&x,&y); x++;y++; scanf("%s",b+1); L2=strlen(b+1); _next(); _kmp(); printf("%d ",ans); } return 0; }

    Hard部分:

    后缀自动机各种不过。应该还是要用后缀数组才行。

    我的代码(没过,小数据没问题)

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<memory>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int maxn=201000;
    char chr[maxn];
    int Le,Ri,Now;
    vector<int>G[maxn];
    struct SAM
    {
        int sz,Last,ch[maxn][26],slink[maxn],maxlen[maxn],ans;
        void init()
        {
            Last=sz=1;G[1].clear();
            memset(ch[1],0,sizeof(ch[1]));
        }
        void add(int x)
        {
              int np=++sz,p=Last;Last=np;
              G[np].clear(); memset(ch[np],0,sizeof(ch[np]));
              maxlen[np]=maxlen[p]+1;
              while(p&&!ch[p][x]) ch[p][x]=np,p=slink[p];
              if(!p) slink[np]=1;
              else {                
                    int q=ch[p][x];
                    if(maxlen[q]==maxlen[p]+1)  slink[np]=q;
                    else {                
                        int nq=++sz;  G[nq].clear();
                        memcpy(ch[nq],ch[q],sizeof(ch[q]));
                        G[nq].assign(G[q].begin(),G[q].end());
                        //G[q].swap(G[nq]);
                        slink[nq]=slink[q],slink[np]=slink[q]=nq;
                        maxlen[nq]=maxlen[p]+1;
                        while(p&&ch[p][x]==q) ch[p][x]=nq,p=slink[p];
                    }
             }
             while(np>1) G[np].push_back(Now),np=slink[np];
        }
        void solve()
        {        
            scanf("%d%d",&Le,&Ri); 
            scanf("%s",chr);
            int Lt=strlen(chr);
            int mp=1,Len=0;ans=0;Le=Le+Lt-1;
            for(int j=0;j<Lt;j++) {
                int x=chr[j]-'a';
                if(ch[mp][x]) { Len++;  mp=ch[mp][x];}
                else {
                    while(mp&&!ch[mp][x]) mp=slink[mp];
                    if(!mp) {  mp=1; Len=0; }
                    else {  Len=maxlen[mp]+1; mp=ch[mp][x]; }
                }
            }
            if(Len==Lt) 
               for(int i=0;i<G[mp].size();i++){
                if(G[mp][i]>=Le&&G[mp][i]<=Ri) ans++;
            }
            printf("%d
    ",ans);
        }
    };
    SAM sam;
    int main()
    {
        sam.init(); int q,l;
        scanf("%s",chr);
        l=strlen(chr);
        for(Now=0;Now<l;Now++) sam.add(chr[Now]-'a');
        scanf("%d",&q);
        while(q--)   sam.solve();     
        return 0;
    }
  • 相关阅读:
    WiFi流量劫持—— 浏览任意页面即可中毒!
    POJ3614防晒霜 这个贪心有点东西(贪心+优先队列)
    7月24日训练记录
    环形均分纸牌问题(中位数)
    7月23日训练总结
    7.22学习总结
    POJ 1176 Party Lamps&& USACO 2.2 派对灯(搜索)
    尘埃落定,以梦为马,不负韶华
    P1522 牛的旅行 Cow Tours(floyd)
    分享一种解题的思想,有关时间复杂度探讨
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8011199.html
Copyright © 2011-2022 走看看