ZOJ 3430
无力吐槽。。
代码如下:
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #include<iostream> 6 using namespace std; 7 const int N = 50010; 8 const int kind = 256; 9 char file[N],val[N]; 10 int digit[N],code[N],Size,vis[N]; 11 12 struct node{ 13 int Next[kind]; 14 int fail; 15 int count; 16 void init() 17 { 18 memset(Next,-1,sizeof(Next)); 19 fail = 0; 20 count = 0; 21 } 22 23 }s[N]; 24 int sind; 25 int q[N],qin,qout; 26 void cas_init() 27 { 28 s[0].init(); 29 sind=1; 30 } 31 32 void ins()//向树中插入字母 33 { 34 int i, j, ind; 35 for(i = ind = 0;code[i] >= 0;i++) 36 { 37 j = code[i];//求出字母在next中的编号 38 if(s[ind].Next[j]== -1)//如果不存在子节点j,则构造新的 39 { 40 s[sind].init();//初始化 41 s[ind].Next[j] = sind++;//连向当前结点,并sind++代表总结点数 42 } 43 ind = s[ind].Next[j]; //向下走 44 } 45 s[ind].count++;//增加离根结点这条路径上字符串的个数,一条路上可能不止一个单词 46 } 47 void make_fail()//构造失配指针 48 { 49 qin = qout = 0;//初始化队列 50 int i,ind,ind_f; 51 for(i=0;i<kind;i++) 52 { 53 if(s[0].Next[i]!=-1) 54 q[qin++]=s[0].Next[i];//先考虑根结点,和根结点相连的都入队 55 } 56 while(qin!=qout) 57 { 58 ind = q[qout++];//记录队首结点 59 for(i = 0;i < kind; i++)//遍历队首结点的Next 60 { 61 // cout<<qin<<" "<<qout<<endl; 62 if(s[ind].Next[i]!=-1)//如果结点Next不为空 63 { 64 q[qin++] = s[ind].Next[i];//将儿子节点入队 65 ind_f = s[ind].fail;//记录节点的失配指针指向 66 while(ind_f>0 && s[ind_f].Next[i]==-1) 67 /*当失配指针不为root时,一直循环直到找到一个结点是儿子是i值或者到了root*/ 68 ind_f = s[ind_f].fail; 69 if(s[ind_f].Next[i]!=-1) //如果当前结点有儿子的话记录下来备用 70 ind_f = s[ind_f].Next[i]; 71 s[s[ind].Next[i]].fail = ind_f; //使当前结点的失配指针指向刚才记录的结点完成失配指针的寻找构造 72 } 73 } 74 } 75 } 76 int fd() 77 { 78 memset(vis,0,sizeof(vis)); 79 int ct = 0; //记录“单词的个数” 80 int di,i,ind ,p; //di为指向“文章”的指针,ind为指向失配结点的指针(即trie树中失配的指针) 81 for(di = ind =0; code[di]>=0; di++) 82 { 83 i = code[di]; 84 while(ind>0 && s[ind].Next[i] == -1) 85 /*当ind指针不是root和找不到结点的儿子是i时一直找下去(类似于KMP中while循环)*/ 86 ind = s[ind].fail; //一直寻找失配指针 87 88 if(s[ind].Next[i]!= -1)//找到了合适的失配指针 89 { 90 ind = s[ind].Next[i]; //指向这个儿子的节点,更新ind的值进行下一次匹配 91 92 p = ind; //用p来临时代替ind 93 while(p>0 && !vis[p]) 94 /* p>0 表示还没到root,count!=-1表示指针前还有单词*/ 95 { 96 ct+=s[p].count;//加上有的单词的个数 97 vis[p]=1; 98 //不重复计算,注意这里很重要 99 p = s[p].fail;//一直寻找失配指针 100 } 101 } 102 } 103 return ct;//返回单词个数 104 } 105 int fun(char ch) //convert char to int 106 { 107 if(ch >= 'A' && ch <= 'Z') return ch - 'A'; 108 if(ch >= 'a' && ch <= 'z') return ch - 'a' + 26; 109 if(ch >= '0' && ch <= '9') return ch - '0' + 52; 110 if(ch == '+') return 62; 111 return 63; 112 } 113 114 void change(char *str) 115 { 116 int i, j, len, t; 117 vector<int> v; 118 memset(digit, 0, sizeof(digit)); 119 for(len = strlen(str); str[len-1] == '='; len--) ; 120 str[len] = '\0'; 121 for(i = 0; i < len; i++) 122 v.push_back(fun(str[i])); 123 for(i = 0; i < v.size(); i++) { 124 for(j = 6 * (i + 1) - 1; j >= 6 * i; j--) { 125 if(v[i]&1) 126 digit[j] = 1; 127 v[i] >>= 1; 128 } 129 } 130 int k = v.size() * 6 / 8; //the number of letter before encode 131 for(i = 0; i < k; i++) { 132 for(t = 0, j = 8 * i; j < 8 * (i + 1); j++) 133 t = (t << 1) + digit[j]; 134 code[i] = t; 135 } 136 code[i] = -1; 137 } 138 139 int main() 140 { 141 ios::sync_with_stdio(false); 142 int n,m; 143 while(cin>>n) 144 { 145 // memset(s,0,sizeof(s)); 146 cas_init(); 147 for(int i = 0;i < n;i ++) 148 { 149 cin>>val; 150 change(val); 151 ins(); 152 } 153 make_fail(); 154 cin>>m; 155 while(m--) 156 { 157 cin>>file; 158 memset(code,0,sizeof(code)); 159 change(file); 160 cout<<fd()<<endl; 161 } 162 cout<<endl; 163 } 164 }
浙公网安备 33010602011771号