1. 程式人生 > >11.3清北集訓_subset分塊思想

11.3清北集訓_subset分塊思想

在這裡插入圖片描述
在這裡插入圖片描述

solution

  1. 我們發現2^16=65536 * 1e5就炸了
  2. 但是2^8=256,再乘上1e5就不怕了
  3. 我們發現a&s=a,把a拆成前8位和後8位 和16位一起算是一樣的
  4. 所以我們搞一個f[pre][suf]表示i^pre=i 且 i=suf 的個數
  5. add和del時列舉前8位加減
  6. cnt時列舉後8位
    在這裡插入圖片描述

code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
inline int read(){
	char ch=' ';int f=1;int x=0;
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int N=255;// 2^8-1

int digit[2333][2333];
int main()
{
	freopen("subset.in","r",stdin);
	freopen("subset.out","w",stdout);
	int n;
	n=read();
	int i,j,k;
	char op[10];
	int x;
	for(j=1;j<=n;j++)
	{
		scanf("%s",op);
		x=read();
		int l=x>>8;int r=x&(N);int f=0;
		if(op[0]=='d') f=-1;
		else if(op[0]=='a') f=1;
		if(op[0]=='a'||op[0]=='d')
		{
			for(i=0;i<=N;i++)
			{
				if((l&i)==l)
				{
					digit[i][r]+=f;
				}
			}
		}
		else
		{
			int ans=0;
			for(i=0;i<=N;i++)
			{
				if((i&r)==i)
				{
					ans+=digit[l][i];
				}
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}