牛客小白91 F---位掩码 拆位计算贡献
题目

是一道位掩码的好题,忍不住想写下题解去记录下,首先暴力做法就不提了,我们要做的就是优化,这里使用的是拆位
比如对于
3 2
11
10
那么对于第一个是 1 第二个是2*0 相加为1 你会发现拆位算
答案是不改变的 此题也是用拆位计算的
直接讲做法 首先外层套个20的循环 里层来个On的循环
然后对于每一个0 1 都需要保存下来 注释都在代码里,可以看懂。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int range = 1e6 + 10;
const int mod = 1e9 + 7;
int n;
int a[range];
int v1, v0;
int ans;
void solve() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int t = 0; t <= 20; t++) {
//拆位 v1v0 只对本次位 有用
v1=v0=0;
for (int i = 1; i <= n; i++) {
if ((a[i] >> t) & 1) {
ans += ((((v0 * (n - i + 1) % mod) * (1 << t)) % mod) * 2) % mod;
//在1--i-1的范围内 所有为1 让v0是指为1的包涵这个1的下标为左端点的区间总数
ans %= mod;
v1 = (v1 + i) % mod;//加上包涵该左端点的所有可能区间总数 以便后续
//当遍历到0时 拿来给0用 把0当作右端点时候 这个v1就要用上了
} else {
ans += ((((v1 * (n - i + 1) % mod) * (1 << t)) % mod) * 2) % mod;
ans %= mod;//需要乘2 手写一遍就会发现要*2
v0 = (v0 + i) % mod;//同上 不过这个0存着后面1用
}
}
}
cout << ans << endl;
return ;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}

浙公网安备 33010602011771号