选数字

\(【题目描述】\)

\(N(N \leq 10^5)\)个数排成一行,有\(Q(Q \leq 10^5)\)组询问,每一组询问有三个整数\(l_i,r_i,x_i\),求在区间\([l_i,r_i]\)中任意找3个数按位或等于\(x_i\)的方案数。

\(【样例输入】\)

10 5
2 4 3 7 6 9 8 7 10 15
1 5 7
2 8 14
3 5 7
1 10 15
6 9 12

\(【样例输出】\)

9
1
1
81
0

\(【考点】\)

位运算、容斥原理

\(【做法】\)


\(【代码】\)

#include<cstdio>
#include<iomanip>
#define int long long
using namespace std;
const int N=1e5+50;
int a[N],n,q;
int cnt[N][280];
int tot[280];
int Calc(int x){return x*(x-1)*(x-2)/6;}//计算组合数C(x,3) 
signed main()
{
	scanf("%lld%lld",&n,&q);
	int l,r,x;
	tot[0]=0,tot[1]=tot[2]=1;
	for(int i=3;i<=255;i++) tot[i]=tot[i/2]+(i&1);//如果当前位i为1,则tot[i]+1
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		for(int j=0;j<=255;j++){
			if((a[i]|j)==j) cnt[i][j]=cnt[i-1][j]+1;//预处理cnt[i][j] 
			else cnt[i][j]=cnt[i-1][j];
		}
	}
	for(int i=1;i<=q;i++){
		int ans=0;
		scanf("%lld%lld%lld",&l,&r,&x);
		for(int j=0;j<=255;j++){
			int t=j|x,p=1;
			if(t!=x) continue;
			t=tot[x]-tot[j];//判断j与x相差的位数为偶数还是奇数 
			if(t&1) p=-1; 
			ans+=p*Calc(cnt[r][j]-cnt[l-1][j]);
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2021-02-04 09:29  lxzy  阅读(95)  评论(0)    收藏  举报