Or三元组 [计数问题]

O r 三 元 组 Or三元组 Or


正 解 部 分 \color{red}{正解部分}

" 前 言 " : "前言": "": 若处理出 s u m [ i , j ] sum[i, j] sum[i,j] 表示前 i i i 个数字 j j j 出现的次数,
预处理时空复杂度为 O ( N ∗ 255 ) O(N*255) O(N255), 单次查询时间复杂度 O ( 255 ∗ 255 ) O(255*255) O(255255), 显然不能过.

记录 s u m [ i , j ] sum[i, j] sum[i,j] 为前 i i i 个数 o r   j = j or\ j = j or j=j 的数字数量,
c n t x = s u m [ r , x ] − s u m [ l − 1 , x ] cnt_x = sum[r, x] - sum[l-1, x] cntx=sum[r,x]sum[l1,x], 则 c n t x cnt_x cntx 个数中 3 3 3 起来并不一定等于 x x x, 可能小于 x x x,
考虑怎么 得到起来等于 x x x 的三元组 个数, 可以使用 容斥,
A n s = C c n t x 3 − C c n t a 1 3 − C c n t a 2 3 ​ ⋯ + ​ ⋯ − ​ ⋯ ​ ⋯ Ans = C_{cnt_x}^3 -C_{cnt_{a_1}}^3-C_{cnt_{a_2}}^3 \dotsi+\dotsi-\dotsi\dotsi Ans=Ccntx3Ccnta13Ccnta23+

o r   x = x or\ x=x or x=x 的数中 与 x x x 二进制相差奇数个 1 1 1 的数 容斥系数为 − 1 -1 1, 否则为 1 1 1.

由于每次容斥最多调用 255 255 255 个数字, 所以单次查询复杂度为 O ( 255 ) O(255) O(255) .


实 现 部 分 \color{red}{实现部分}

注意不能写成下面这个代码, 因为这样会计算重复 .

#include<bits/stdc++.h>
#define reg register

const int maxn = 1e5 + 5;

int N;
int M;
int Ans;
int A[maxn];
int pw[20];
int sum[maxn][257];

void DFS(int opt, int x, int r, int l){
        int cur_cnt = sum[r][x] - sum[l-1][x];
        if(opt & 1) Ans += (cur_cnt>=3)*cur_cnt*(cur_cnt-1)*(cur_cnt-2)/6;
        else Ans -= (cur_cnt>=3)*cur_cnt*(cur_cnt-1)*(cur_cnt-2)/6;
        for(reg int i = 0; pw[i] <= x; i ++)
                if(pw[i] & x) DFS(opt^1, x^pw[i], r, l);
}

int main(){
        scanf("%d%d", &N, &M);
        for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]); 
        pw[0] = 1;
        for(reg int i = 1; i <= 10; i ++) pw[i] = pw[i-1] << 1;
        for(reg int j = 1; j <= 255; j ++)
                for(reg int i = 1; i <= N; i ++) sum[i][j] = sum[i-1][j] + ((A[i]|j) == j);
        for(reg int i = 1; i <= M; i ++){
                int l, r, x;
                scanf("%d%d%d", &l, &r, &x);
                Ans = 0;
                DFS(1, x, r, l);
                printf("%d\n", Ans);
        }
        return 0;
}

这个是对的 .

#include<bits/stdc++.h>
#define reg register
typedef long long ll;

const int maxn = 1e5 + 5;

int N;
int M;
int cnt_1;
int A[maxn];
int pw[20];
int tmp_1[20];
int sum[maxn][257];

ll Ans;

void DFS(int opt, int x, int cur, int r, int l){
	if(x == cnt_1 + 1){
	     int cur_cnt = sum[r][cur] - sum[l-1][cur];
	     if(opt & 1) Ans += 1ll*(cur_cnt>=3)*cur_cnt*(cur_cnt-1)*(cur_cnt-2)/6;
	     else Ans -= 1ll*(cur_cnt>=3)*cur_cnt*(cur_cnt-1)*(cur_cnt-2)/6;
	     return ;
	}
        DFS(opt, x + 1, cur, r, l);
        DFS(opt^1, x + 1, cur^tmp_1[x], r, l);
}

int main(){
        freopen("Or.in", "r", stdin);
        freopen("Or.out", "w", stdout);
        scanf("%d%d", &N, &M);
        for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]); 
        pw[0] = 1;
        for(reg int i = 1; i <= 10; i ++) pw[i] = pw[i-1] << 1;
        for(reg int j = 1; j <= 255; j ++)
                for(reg int i = 1; i <= N; i ++) sum[i][j] = sum[i-1][j] + ((A[i]|j) == j);
        for(reg int i = 1; i <= M; i ++){
                int l, r, x;
                scanf("%d%d%d", &l, &r, &x);
                Ans = 0;
                cnt_1 = 0;
                for(reg int j = 0; j <= 10; j ++)
                	if(pw[j] & x) tmp_1[++ cnt_1] = pw[j];
                DFS(1, 1, x, r, l);
                printf("%lld\n", Ans);
        }
        return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值