【题解】
给你一个01串。从右到左对应了每个位置上的要求:0该位置为偶数。1该位置为奇数.
如果01串和要判断的数字不一样。谁短谁前面就补0;
我们不管谁短。直接在输入的数字前面补0至18位就好。
然后用字典树来操作。
插入数字的时候。不要具体记录这个数字是什么(没用!),只要知道这个数字是奇数还是偶数就行了嘛。所以93432你就记录11010.
不要被惯性思维影响!
直接记录数字会T!
然后字典树的域要记录以这个节点为终点的数字个数。
每次到这个节点累加这个就可以了。
【代码】
#include <cstdio> #include <cstring> using namespace std; const int MAX_SIZE = 2000000; int t; int tree[MAX_SIZE][2] = { 0 },totn = 0,ans = 0; int e[MAX_SIZE] = { 0 }, stop[MAX_SIZE] = { 0 }; char op[5], dig[30]; void insert() { int temp = 0; int len = 18; for (int i = len-1; i >=0; i--) { int d = dig[i] - '0'; d = d % 2;//直接记录是奇数还是偶数就可以了。 if (tree[temp][d] == 0) tree[temp][d] = ++totn; temp = tree[temp][d]; stop[temp]++; } e[temp]++; } void de_lete() { int temp = 0; int len = 18; for (int i = len-1; i >=0; i--) { int d = dig[i] - '0'; d = d % 2; temp = tree[temp][d]; stop[temp]--; } e[temp]--; } void dfs(int rt, int len) //用dfs来累加答案。 { ans += e[rt]; if (len < 0) return; int d = dig[len] - '0'; if (tree[rt][d]) dfs(tree[rt][d], len - 1); } void get_ans() { int temp = 0; int len = 18; dfs(temp, len - 1); } void input_data() { scanf("%d", &t); char s1[30]; for (int i = 1; i <= t; i++) { scanf("%s%s", op, s1); int len = strlen(s1); for (int i = 0; i <= 18 - len - 1; i++)//补零 dig[i] = '0'; dig[18 - len] = ' '; strcat(dig, s1);//最后dig记录的是补0后的字符 if (op[0] == '+') insert(); else if (op[0] == '-') de_lete(); else { ans = 0; get_ans(); printf("%d ", ans); } } } int main() { //freopen("F:\rush.txt", "r", stdin); input_data(); return 0; }