送分题 [组合计数]

送 分 题 送分题


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

考虑每一位对答案的贡献, 在长度为 N N N 的序列中, 现在计算第 b i t bit bit 位的答案,
b i t bit bit 位 为 1 1 1 的数量为 n 1 n_1 n1, 为 0 0 0 的数量为 n 0 n_0 n0, x + y = N x+y = N x+y=N,

对答案的贡献为 ( ∑ i = 1 n 1   [ i % 2 = 1 ] ( N i ) x i ) × ( ∑ i = 0 n 0 ( N i ) x i ) \left(\sum\limits_{i=1}^{n_1}\ [i\%2 =1]\begin{pmatrix} N \\ i \end{pmatrix}x^i \right) \times \left( \sum\limits_{i=0}^{n_0}\begin{pmatrix} N \\ i \end{pmatrix}x^i \right) (i=1n1 [i%2=1](Ni)xi)×(i=0n0(Ni)xi) .

根据 二项式定理 化第二项为: ( x + 1 ) n 0 (x+1)^{n_0} (x+1)n0 .

将第一项化为: ∑ i = 0 n 1   ( ( − 1 ) i + 1 + 1 ) ( N i ) x i 2 \frac{\sum\limits_{i=0}^{n_1}\ \left((-1)^{i+1}+1\right) \begin{pmatrix} N \\ i \end{pmatrix}x^i}{2} 2i=0n1 ((1)i+1+1)(Ni)xi

将括号拆开得到: − ∑ i = 0 n 1 ( N i ) ( − x ) i + ∑ i = 0 n 1 ( N i ) x i 2 \frac{-\sum\limits_{i=0}^{n_1}\begin{pmatrix} N \\ i\end{pmatrix}(-x)^i+\sum\limits_{i=0}^{n_1} \begin{pmatrix} N \\ i\end{pmatrix}x^i}{2} 2i=0n1(Ni)(x)i+i=0n1(Ni)xi

再使用 二项式定理 继续化简得到: − ( − x + 1 ) n 1 + ( x + 1 ) n 1 2 \frac{-(-x+1)^{n_1} + (x+1)^{n_1}}{2} 2(x+1)n1+(x+1)n1

∴ a n s = ∑ b i t = 0 30 − ( − x + 1 ) n 1 + ( x + 1 ) n 1 2 × ( x + 1 ) n 0 × 2 b i t \therefore ans = \sum\limits_{bit=0}^{30} \frac{-(-x+1)^{n_1} + (x+1)^{n_1}}{2} \times (x+1)^{n_0} \times 2^{bit} ans=bit=0302(x+1)n1+(x+1)n1×(x+1)n0×2bit .

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

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

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 1e5 + 10;
const int mod = 998244353;

int N;
int M;
int A[maxn];
int pw[maxn];
int s[32][maxn];

int Ksm(int a, int b){ int s=1; while(b){if(b&1)s=1ll*s*a%mod;a=1ll*a*a%mod;b>>=1;} return s; }

void Work(){
        int l = read(), r = read(), x = read(), Ans = 0;
        for(reg int bit = 30; bit >= 0; bit --){
                int n1 = s[bit][r] - s[bit][l-1], n0 = r-l+1-n1;
                int res = (Ksm(x+1, n1) - Ksm((1-x+mod)%mod, n1) + mod) % mod;
                res = 1ll*res*Ksm(2, mod-2) % mod;
                res = 1ll*res * Ksm(x+1, n0) % mod;
                res = 1ll*res*pw[bit] % mod;
                Ans = (Ans + res) % mod;
        }
        printf("%d\n", Ans);
}

int main(){
        N = read(), M = read();
        for(reg int i = 1; i <= N; i ++) A[i] = read();
        pw[0] = 1; for(reg int i = 1; i <= 30; i ++) pw[i] = 2ll*pw[i-1] % mod;
        for(reg int i = 0; i <= 30; i ++)
                for(reg int j = 1; j <= N; j ++){
                        if(A[j] & (1 << i)) s[i][j] ++;
                        s[i][j] += s[i][j-1];
                }
        for(reg int i = 1; i <= M; i ++) Work();
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值