Codeforces Round #371 (Div. 2) - C
题目链接:http://codeforces.com/contest/714/problem/C
题意:给定t个操作。维护一个可重复集合。操作分为3种: + num:向集合中插入数num; - num:从集合中删除数num; ? string(01串):查询集合有多少个数满足和01串匹配。 匹配规则:把集合中的数的转化为以每一位的奇偶性组成的01串,然后匹配时如果string长度比集合中的数小时,在string前面补0. 如果集合中的数的长度比string短时,在数的前面补0。
思路;因为有插入删除和匹配。而且是01串。所以我们可以构造一棵01字典树来存集合中的数字。 插入对应字典树插入。删除对应字典树值-1.匹配查询则稍微对string做下处理。定义pos为string从左到右第一个'1'的下标(不存在则为-1)。然后匹配时逆序匹配,当匹配到pos位置时,当前字典树的子树的根为x。则一直沿着x的'0'子树下去,然后统计结点上的贡献。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<queue> #include<vector> #include<time.h> #include<cmath> #include<set> using namespace std; typedef long long int LL; const int MAXN = 1000000 + 5; struct Trie{ int val; int child[2]; Trie(){ val = 0; memset(child, 0, sizeof(child)); } }trie[MAXN]; int trieN; void Insert(char *str){ int d, x = 0; for (int i = strlen(str)-1; i >= 0;i--){ d = (str[i] - '0') % 2; if (trie[x].child[d] == 0){ trie[x].child[d] = ++trieN; } x = trie[x].child[d]; } trie[x].val++; } int Search(char *str){ int d, x = 0,cnt=0,pos=-1; for (int i = 0; str[i]; i++){ if (str[i] == '1'){ pos = i; break; } } if (pos != -1){ for (int i = strlen(str) - 1; i >= 0; i--){ d = (str[i] - '0') % 2; if (trie[x].child[d] == 0){ return 0; } x = trie[x].child[d]; if (i == pos){ break; } //之后的string都是0 } } cnt += trie[x].val; while ((x = trie[x].child[0])!=0){ //沿着当前的子树根一直往'0'子树走 cnt += trie[x].val; } return cnt; } void Delete(char *str){ int x = 0, d; for (int i = strlen(str) - 1; i >= 0; i--){ d = (str[i] - '0') % 2; if (trie[x].child[d] == 0){ return; } x = trie[x].child[d]; } trie[x].val == 0 ? trie[x].val = 0 : trie[x].val--; } int main(){ #ifdef kirito freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int n; char op[2], num[20]; while (~scanf("%d", &n)){ trieN = 0; for (int i = 0; i < n; i++){ scanf("%s %s", op, num); switch (op[0]){ case '+': Insert(num); break; case '-': Delete(num); break; default: printf("%d\n",Search(num)); } } } return 0; }