poj4052 Hrinity

Hrinity

题目背景:

POJ - 4052 

分析:明明不算太难的题,我前前后后断断续续调了一个月······也不知道当时怎么想的,其实说白了就是三个步骤,一把所有的模式串建成自动机,二用匹配串跑一遍,标记所有的被匹配的串,然后针对所有匹配上的串清除其子串,之后统计一下答案即可。中间本人出问题的点已经在代码中进行了标注。

Source:

#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
         
         
#include 
         
         
           #include 
          
            #include 
           
             #include 
            
              using namespace std; const int MAXN = 3010000 + 30; char s[5101000]; char s1[2510]; int n, tot, cas; int f[MAXN][26], fail[MAXN], first[MAXN]; int top; char ss1[1500], sss[2600][1200], ss[5100010]; bool able[MAXN], vis[MAXN]; void build_trie(char *s, int num) { int position = 0; for(int i = 0; s[i]; ++i) { /*注意最好不要用strlen预处理长度,不然时间复杂度要增加很多*/ if(!f[position][s[i] - 'A']) { f[position][s[i] - 'A'] = ++tot; memset(f[tot], 0, sizeof(f[tot])), first[tot] = 0, fail[tot] = 0; /*此处模拟动态开点,相对而言更节约时间*/ } position = f[position][s[i] - 'A']; } first[position] = num; /*记录当前结点的结束串编号*/ } void build_AC() { queue 
             
               q; q.push(0); while(!q.empty()) { int j = q.front(); q.pop(); for(int i = 0; i < 26; ++i) { if(f[j][i]) { if(j) fail[f[j][i]] = f[fail[j]][i]; q.push(f[j][i]); } else f[j][i] = f[fail[j]][i]; } } } void change(char *s, char* ss, int num) { top = 0; int len = strlen(s); for(int i = 0; i < len;) { /*注意把原串变化成普通串一定要头脑清醒,比较容易出错*/ if(s[i] == '[') { int v = 0; i++; while(isdigit(s[i])) v = (v << 3) + (v << 1) + (s[i] ^ '0'), i++; for(int j = 1; j <= v; ++j) ss[top++] = s[i]; i += 2; } else ss[top++] = s[i], i++; } ss[top] = '\0'; /*为了节约时间我没有初始化所以最后一定加\0*/ if(num) strcpy(sss[num], ss); } void read() { scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%s", s1), change(s1, ss1, i), build_trie(sss[i], i); scanf("%s", s), change(s, ss, 0); } void get() { int position = 0; for(int i = 0; ss[i]; ++i) { position = f[position][ss[i] - 'A']; int temp = position; if (first[position]) vis[temp] = true, able[first[temp]] = true; else { /*注意这个else不能省,之前竟然把这一个去掉了*/ for (; !vis[temp] && temp; temp = fail[temp]) vis[temp] = true, able[first[temp]] = true; } } memset(vis, 0, sizeof(vis)); for(int i = 1; i <= n; ++i) { if(able[i]) { int position = 0; for(int j = 0; sss[i][j]; ++j) { position = f[position][sss[i][j] - 'A']; int temp = position; for (; temp && !vis[temp]; temp = fail[temp]) { if (first[temp] != i) vis[temp] = true; /*注意这个判定条件,当前的first[temp] = i时不能标记*/ if (first[temp] && first[temp] != i) able[first[temp]] = false; } } } } int ans = 0; for(int i = 1; i <= n; ++i) if(able[i]) ans++; printf("%d\n", ans); } void clear() { memset(vis, 0, sizeof(vis)); memset(able, 0 ,sizeof(able)); memset(f[0], 0, sizeof(f[0])); /*对于f[0]的初始化绝对不能少······*/ tot = cas = 0; } int main() { int t; scanf("%d", &t); while(t--) { read(); build_AC(); get(); clear(); } return 0; } 
              
             
            
           
         
        
        
       
       
      
      
     
     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值