zoukankan      html  css  js  c++  java
  • luogu P2353 背单词

    二次联通门 : luogu P2353 背单词

    一眼看过去, 卧槽,AC自动机板子题

    写完后T成SB

    卧槽10^6 做个篮子啊

    重构思路。。。

    恩。。Hash + 莫队。。。

    恶心啊。。

    找xxy dalao, AC自动机 + 前缀和

    码完WA成SB

    去群里找dalao

    大佬告诉了我前缀和的正确使用姿势。。。

    然后就依然WA成SB

     做个毛线

    贴一个AC自动机的30代码

    #include <cstdio>
    #include <cstring>
    #include <queue>
    
    #define Max 3000090
    
    void read (int &now)
    {
        now = 0;
        register char word = getchar ();
        while (word < '0' || word > '9')
            word = getchar ();
        while (word >= '0' && word <= '9')
        {
            now = now * 10 + word - '0';
            word = getchar ();
        }
    }
    
    char __txt[Max];
    
    struct T_D
    {
        T_D *child[26];
    
        T_D *Fail;
        int Count;
        
        int number;
        T_D ()
        {
            for (int i = 0; i < 26; i ++)
                this->child[i] = NULL;
            
            Count = 0;
            Fail = NULL;
            number = 0;
        }
    };
    
    int List[Max << 1];
    int List_Cur;
    
    bool visit[Max];
    
    class AC_Type
    {
    
        private :
    
            T_D *Root;
            int Trie_Count;
    
        
        public :
    
            void Insert (char *key)
            {
                T_D *now = Root;
    
                int Len = strlen (key);
                int Id;
    
                for (int i = 0; i < Len; i ++)
                {
                    Id = key[i] - 'a';
                    if (now->child[Id] == NULL)
                    {
                        now->child[Id] = new T_D;
                        now->child[Id]->number = ++ Trie_Count;
                    }
    
                    now = now->child[Id];
                }
                now->Count ++;
            }
    
            AC_Type ()
            {
                Trie_Count = 0;
                Root = new T_D ;
                Root->number = ++ Trie_Count;
            }
    
            void Build_AC ()
            {
                std :: queue <T_D *> Queue;
    
                Queue.push (Root);
                
                T_D *now, *pos;
                while (!Queue.empty ())
                {
                    now = Queue.front ();
                    Queue.pop ();
    
                    pos = NULL;
    
                    for (int i = 0; i < 26; i ++)
                    {
                        if (now->child[i] == NULL)
                            continue;
                        if (now == Root)
                            now->child[i]->Fail = Root;
                        else
                        {
                            for (pos = now->Fail; pos; pos = pos->Fail)
                                if (pos->child[i])
                                {
                                    now->child[i]->Fail = pos->child[i];
                                    break;
                                }
                            if (pos == NULL)
                                now->child[i]->Fail = Root;
                        }
                        Queue.push (now->child[i]);
                    }
                }
            }
    
            int Query (int x, int y)
            {
                T_D *now, *pos;
                
                int Id ;
                now = Root;
                int res = 0;
                
                for (int i = x; i <= y; i ++)
                {
                    Id = __txt[i] - 'a';
                    for (; now != Root && now->child[Id] == NULL; now = now->Fail);
                    
                    now = now->child[Id];
                    if (now == NULL)
                        now = Root;
    
                    for (pos = now; pos != Root && !visit[pos->number]; pos = pos->Fail)
                    {
                        res += pos->Count;
                        visit[pos->number] = true;
                        List[++ List_Cur] = pos->number;
                    }
    
                    for (int j = 1; j <= List_Cur; j ++)
                        visit[List[j]] = false;
    
                    List_Cur = 0;
            
                }
            
                return res;
            }
    
    };
    
    AC_Type Make;
    
    int N, Q;
    char line[Max];
    
    int main (int argc, char *argv[])
    {
        read (N);
        read (Q);
        scanf ("%s", __txt);
        
        for (int i = 1; i <= N; i ++)
        {
            scanf ("%s", line);
            Make.Insert (line);
        }
        
        Make.Build_AC ();
        
        for (int x, y; Q --; )
        {
            read (x);
            read (y);
                        
            printf ("%d
    ", Make.Query (-- x, -- y));
        }
    
        return 0;
    }

     再贴个AC自动机思路正确但由于细节问题WA成dog的代码

    #include <cstdio>
    #include <cstring>
    #include <queue>
    
    #define Max 1000090
    
    #define DEBUG for (int i = 1; i <= strlen (__txt); i ++)
                    printf ("%d  ", __sum[i]);
                    putchar ('
    ');
                    
    void read (int &now)
    {
        now = 0;
        register char word = getchar ();
        while (word < '0' || word > '9')
            word = getchar ();
        while (word >= '0' && word <= '9')
        {
            now = now * 10 + word - '0';
            word = getchar ();
        }
    }
    
    char __txt[Max];
    
    struct T_D
    {
        T_D *child[26];
    
        T_D *Fail;
        int Count;
        
        int number;
        T_D ()
        {
            for (int i = 0; i < 26; i ++)
                this->child[i] = NULL;
            
            Count = 0;
            Fail = NULL;
            number = 0;
        }
    };
    
    int __sum[Max];
    
    class AC_Type
    {
    
        private :
    
            T_D *Root;
            int Trie_Count;
    
        
        public :
    
            void Insert (char *key)
            {
                T_D *now = Root;
    
                int Len = strlen (key);
                int Id;
    
                for (register int i = 0; i < Len; i ++)
                {
                    Id = key[i] - 'a';
                    if (now->child[Id] == NULL)
                    {
                        now->child[Id] = new T_D;
                        now->child[Id]->number = ++ Trie_Count;
                    }
    
                    now = now->child[Id];
                }
                now->Count ++;
            }
    
            AC_Type ()
            {
                Trie_Count = 0;
                Root = new T_D ;
                Root->number = ++ Trie_Count;
            }
    
            void Build_AC ()
            {
                std :: queue <T_D *> Queue;
    
                Queue.push (Root);
                
                T_D *now, *pos;
                while (!Queue.empty ())
                {
                    now = Queue.front ();
                    Queue.pop ();
    
                    pos = NULL;
    
                    for (register int i = 0; i < 26; i ++)
                    {
                        if (now->child[i] == NULL)
                            continue;
                        if (now == Root)
                            now->child[i]->Fail = Root;
                        else
                        {
                            for (pos = now->Fail; pos; pos = pos->Fail)
                                if (pos->child[i])
                                {
                                    now->child[i]->Fail = pos->child[i];
                                    break;
                                }
                            if (pos == NULL)
                                now->child[i]->Fail = Root;
                        }
                        Queue.push (now->child[i]);
                    }
                }
            }
    
            int Query ()
            {
                T_D *now, *pos;
                
                int Id ;
                now = Root;
                int res = 0;
                int Len = strlen (__txt);
                
                for (register int i = 0; i < Len; i ++)
                {
                    Id = __txt[i] - 'a';
                    for ( ; now != Root && now->child[Id] == NULL; now = now->Fail);
                    
                    now = now->child[Id];
                    if (now == NULL)
                        now = Root;
    
                    for (pos = now; pos != Root && pos->Count >= 0; pos = pos->Fail)
                    {
                        __sum[i + 1] += pos->Count;
                        pos->Count = -1;
                    }
                    __sum[i + 1] += __sum[i];
            
                }
            
                return res;
            }
    
    };
    
    AC_Type Make;
    
    int N, Q;
    char line[Max];
    
    int length[Max];
    
    int main (int argc, char *argv[])
    {
    
        read (N);
        read (Q);
        scanf ("%s", __txt);
        
        for (int i = 1; i <= N; i ++)
        {
            scanf ("%s", line);
            Make.Insert (line);
            length[i] = strlen (line);
        }
        
        Make.Build_AC ();
        Make.Query ();
           register int Answer, now;
           
        for (int x, y; Q --; )
        {
            Answer = 0;
            
            read (x);
            read (y);
            
            for (int i = 1; i <= N; i ++)
                Answer += (__sum[y - length[i]] - __sum[x - 1]);
            
            printf ("%d
    ", Answer);
        }
    
        return 0;
    }

    最后再贴个正解。。。。是我想麻烦了。。kmp或者hash都可以。。

    /*
        luogu P2353 背单词
        
        由于M很小
        可以进行M次kmp
        
        统计出M个前缀和
        
        每次输出时把 M 个前缀和扫一遍 
        注意区间的开闭问题
        
        由于r端点的串不包含在所查询的区间内
        所以要减去当前模式串的长度 
    
    */
    #include <cstdio>
    #include <cstring>
    
    #define Max 1000090
    
    void read (int &now)
    {
        now = 0;
        register char word = getchar ();
        while (word > '9' || word < '0')
            word = getchar ();
        while (word >= '0' && word <= '9')
        {
            now = now * 10 + word - '0';
            word = getchar ();
        }
    }
    
    int __next[Max];
    
    void Get_Next (char *line)
    {
        __next[0] = -1;
    
        for (int pos_1 = 0, pos_2 = -1, Len = strlen (line); pos_1 < Len; )
            if (pos_2 == -1 || line[pos_1] == line[pos_2])
            {
                pos_1 ++;
                pos_2 ++;
                __next[pos_1] = pos_2;
            }
            else
                pos_2 = __next[pos_2];
        
    }
    
    int __sum[Max][Max / 100000 + 1];
    
    void Kmp (char *line, char *__txt, int number)
    {
        for (int Len_txt = strlen (__txt), Len = strlen (line), pos_1 = 0, pos_2 = 0; pos_1 <= Len_txt; )
        {
            if (pos_2 == -1 || __txt[pos_1] == line[pos_2])
            {
                pos_1 ++;
                pos_2 ++;
            }
            else
                pos_2 = __next[pos_2];
            if (pos_2 == Len)
            {
                __sum[pos_1][number] ++;
                pos_2 = __next[pos_2];
            }
        }
    }
    
    char __txt[Max];
    
    int length[Max];
    char line[Max];
    
    int main (int argc, char *argv[])
    {
        int N, M;
        
        read (N);
        read (M);
        
        scanf ("%s", __txt);
        
        int Len_txt = strlen (__txt);
        
        for (int i = 1; i <= N; i ++)
        {
            scanf ("%s", line);
            
            Get_Next (line);
            Kmp (line, __txt, i);
            
            length[i] = strlen (line);
        }
        
        for (int i = 1; i <= Len_txt; i ++) // 把每个模式串的前缀和分开存 
            for (int j = 1; j <= N; j ++)
                __sum[i][j] += __sum[i - 1][j];
        
        for (int i = 1, x, y, Answer; i <= M; i ++)
        {
            read (x);
            read (y);
            Answer = 0;
            
            for (int j = 1; j <= N; j ++)
                if (x - 1 <= y - length[j])
                    Answer += __sum[y][j] - __sum[x + length[j] - 2][j];
        
            printf ("%d
    ", Answer);
        }
        return 0;
    }
  • 相关阅读:
    【OpenCV】SIFT原理与源码分析:方向赋值
    【OpenCV】SIFT原理与源码分析:关键点搜索与定位
    【OpenCV】SIFT原理与源码分析:DoG尺度空间构造
    【OpenCV】SIFT原理与源码分析
    在Android 下写一个检测软件版本号 以自动升级APP 的插件
    Android开发-eclipse+phonegap(Cordova)环境搭建
    phonegap(cordova)从手机app跳转到web页面在跳转回APP本地页面思路
    黑板客爬虫闯关第一关、第二关
    scrapy实战
    scrapy爬虫框架
  • 原文地址:https://www.cnblogs.com/ZlycerQan/p/7043850.html
Copyright © 2011-2022 走看看