POJ 4052 金华邀请赛I题

这题当时比赛的时候,题目看了好久,没看懂(英语6级没过的压力很大啊),当时想先敲E题(后来事实证明这个选择是错误的。。E题到现在都不知道哪出错了)

其实题目就是给出N个字符串,如果S2包含S1,如果S2在文章中的话,就只计算S2,而不计算S1.反之亦然。

比赛时苦苦纠结于到底什么是text finger print。看懂题目后这题就是一个AC自动机的水题。

直接上代码

#include<iostream>

#include<cstdio>

#include<queue>

#include<string>

#include<vector>

#include<algorithm>

#define id(x) ((x) - ('A'))

#define MAXN 3000001

using namespace std;

struct trie {

    trie *next[26];

    trie *fail;

    int id;    

}tree[MAXN],*head;

string finger[2504];

vector<int> sub[2504];   //记录第i个字符串是哪些字符串的子串 



bool cmp(const string &p, const string &q)//先按字符串长度排序,因为稍长的字符串肯定不是稍短的字符串的子串 

{

  return p.length() < q.length();  

}



int COUNT;



int pow(int x)

{

    if (x == 0)return 1;

    int sum = 1;

    for (int i(0); i<x; ++i) {

        sum *= 10;

    }    

    return sum;

}



void ini()

{

    COUNT = 1;

    head = &tree[0];

    for (int i(0); i<2501; ++i) {

      sub[i].clear();

      finger[i].clear();

    }

    for (int i(0); i<26; ++i) {

        head->next[i] = NULL;    

    }    

    head->fail = head;

    head->id = 0;

}



void insert(const string &p,int cnt)

{

    trie *temp = head;

    for (int i(0); i<p.length(); ++i) {

        if (temp->next[id(p[i])] == NULL) {

            temp->next[id(p[i])] = &tree[COUNT++];

            for (int i(0); i<26; ++i) {

                tree[COUNT-1].next[i] = NULL;    

            }    

            tree[COUNT-1].fail = NULL;

            tree[COUNT-1].id = 0;

        }

        temp = temp->next[id(p[i])];    

    }

    temp->id = cnt + 1;

    temp = head;

    for (int i(p.length() - 1); i>=0; --i) {

        if (temp->next[id(p[i])] == NULL) {

            temp->next[id(p[i])] = &tree[COUNT++];    

            for (int i(0); i<26; ++i) {

                tree[COUNT-1].next[i] = NULL;    

            }

            tree[COUNT-1].fail = NULL;

            tree[COUNT-1].id = 0;

        }

        temp = temp->next[id(p[i])];    

    }

    temp->id = cnt + 1;    

}



void AC_Construct()

{

    queue<trie*> Q;

    for (int i(0); i<26; ++i) {

        if (head->next[i] != NULL) {

            head->next[i]->fail = head;

            Q.push(head->next[i]);    

        }    

    }

    while (!Q.empty()) {

        trie *front = Q.front();

        Q.pop();

        for (int i(0); i<26; ++i) {

            if (front->next[i] != NULL) {

                Q.push(front->next[i]);

                trie *temp = front->fail;

                while (temp != head && temp->next[i] == NULL) {

                    temp = temp->fail;    

                }

                if (temp->next[i] != NULL) {

                    front->next[i]->fail = temp->next[i];    

                }    else {

                    front->next[i]->fail = temp;    

                }

            }    

        }    

    }    

}



void deal(string &data, const string &s) //把带括号的字符串转化为不带括号的字符串 

{

    for (int i(0); i<s.length(); ++i) {

        if (s[i] == '[') {

            vector<char> num;

            int j = i+1;

            while ('0' <= s[j] && s[j] <= '9')num.push_back(s[j++]);

            int cnt = 0;

            for (int k(0); k<num.size(); ++k) {

                cnt += (num[k] - '0')*pow(num.size() - k - 1);    

            }

            while (cnt--) {

                data += s[j];    

            }

            i = j + 1;    

        }    else {

            data += s[i];    

        }    

    }    

}



void search(const string &data, int n, int &len)

{

    bool vis[2504] = {false};

    trie *temp = head,*p;

    for (int i(0); i<data.length(); ++i) {

        while (temp != head && temp->next[id(data[i])] == NULL) {

            temp = temp->fail;    

        }

        if (temp->next[id(data[i])] != NULL) {

            temp = temp->next[id(data[i])];

            vis[temp->id] = true;    

        }

       /* p = temp->fail;                                         //本来应该加上这段的,不过我也不知道,为什么不加也能AC 

        while (p != NULL && p != head && !vis[p->id]) {

          vis[p->id] = true;  

        }*/

    }

    if (n != len) {               //如果第i个字符串是n+1的子串的话,就把n+1放进sub[i]里面 

      for (int i(1); i<=n; ++i) {

        if (vis[i]) {

          sub[i].push_back(n+1);    

        }  

      }

    } else {

      for (int i(1); i<=len; ++i) {     //文章中判断第i个字符串是否包含在里面,如果包含的话,就检查第i个字符串是哪些字符串的子串 

        if (vis[i]) {                   //然后看这些串是否也包含在文章里,如果包含的话,就把VIS[I]变成false 

          for (int j(0); j<sub[i].size(); ++j) {

            if (vis[sub[i][j]]) {

              vis[i] = false;

              break;

            } 

          } 

        }  

      }

      int cnt(0);

      for (int i(1); i<=len; ++i) {  //检查每个字符串有多少包含在文章里 

        if (vis[i])++cnt;  

      }

      len = cnt;    

    }    

}



int main()

{

    int T;

    int n;

    cin>>T;

    while (T--) {

        cin>>n;

        string data,s;

        ini();

        for (int i(0); i<n; ++i) {

            string temp;

            cin>>temp;

            deal(finger[i],temp);   

        }

        sort(finger,finger+n,cmp);

        for (int i(0); i<n; ++i) {

          insert(finger[i],i);

        }

        AC_Construct();

        for (int i(0); i<n; ++i) {

          search(finger[i],i,n);

        }  

        cin>>data;

        deal(s,data);

        search(s,n,n);

        cout<<n<<endl;

    }

    return 0;

}

  

你可能感兴趣的:(poj)