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;
}

  

posted on 2012-05-11 22:23  Dev-T  阅读(524)  评论(0编辑  收藏  举报