题目描述:
一开始你有一个空集,集合可以出现重复元素,然后有 Q 个操作:
1、add s
在集合中加入数字 s 。
2、del s
在集合中删除数字 s 。保证 s 存在。如果有多个 s,只删除一个即可。
3、 cnt s
查询满足 a&s=a 条件的 a 的个数。
输入格式:
第一行一个整数 Q 接下来 Q 行,每一行都是 3 个操作中的一个。
输出格式:
对于每个 cnt 操作输出答案。
样例输入:
7
add 11
cnt 15
add 4
add 0
cnt 6
del 4
cnt 15
样例输出:
1
2
2
数据规模:
对于 30% 的数据满足:1≤n≤1000;
一开始你有一个空集,集合可以出现重复元素,然后有 Q 个操作:
1、add s
在集合中加入数字 s 。
2、del s
在集合中删除数字 s 。保证 s 存在。如果有多个 s,只删除一个即可。
3、 cnt s
查询满足 a&s=a 条件的 a 的个数。
输入格式:
第一行一个整数 Q 接下来 Q 行,每一行都是 3 个操作中的一个。
输出格式:
对于每个 cnt 操作输出答案。
样例输入:
7
add 11
cnt 15
add 4
add 0
cnt 6
del 4
cnt 15
样例输出:
1
2
2
数据规模:
对于 30% 的数据满足:1≤n≤1000;
对于 100% 的数据满足:1≤n≤200000;0<s<2^16
这题挺有意思的
主要是用到分块的思想,看到s那么小,我们可以考虑把他拆成两部分,即前八位和后八位
然后记一个a[pre][suf]为前八位为pre,后八位为suf的子集的数的个数
修改的时候,直接枚举suf即可
查询的时候,枚举pre累加即可
代码:
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int INF = 2147483647;
char s[40];
int a[300][300],n,u;
inline LL getint()
{
LL ret = 0,f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret * f;
}
inline int prefix(int x)
{
return x >> 8;
}
inline int suffix(int x)
{
return x & u;
}
int main()
{
n = getint();
u = 255;
for (int i = 1; i <= n; i++)
{
scanf("%s",s); int k = getint(),ret = 0;
if (!strcmp(s,"cnt"))
{
int pre = prefix(k),suf = suffix(k);
for (int j = pre; j; j = j - 1 & pre) ret += a[j][suf];
ret += a[0][suf];
printf("%d\n",ret);
}
if (!strcmp(s,"add"))
{
int pre = prefix(k),suf = suffix(k);
for (int j = u ^ suf; j; j = j - 1 & (u ^ suf))
a[pre][j ^ suf]++;
a[pre][suf]++;
}
if (!strcmp(s,"del"))
{
int pre = prefix(k),suf = suffix(k);
for (int j = u ^ suf; j; j = j - 1 & (u ^ suf))
a[pre][j ^ suf]--;
a[pre][suf]--;
}
}
return 0;
}