Codeforces Round #441 (Div. 2)F. High Cry 按位考虑 + 思维

来源:互联网 发布:佐治亚南方大学 知乎 编辑:程序博客网 时间:2024/06/09 14:54

题意 :就是给你 n 个数让你求满足 这个区间内最大的数小于这个区间内所有数或起来的区间个数。
题解 : 正面处理这个问题比较麻烦我们就先求出不满足的区间,然后用总的区间减去,不满足的就是答案。
剩下的问题就是怎么求不满足的区间呢 ?
首先我们要求出每个数的控制范围 (就是说掌控的意思是这个数or所有其他数等于自己)
首先按位考虑这个问题 如果当前的数的某一位是1那么这一位就可以不考虑,如果这一位是零那么考虑这一位是1的最靠近 当前考虑的数的位置。并且记录下来,正着做一遍,反着做一遍,就可以得到这个的控制的范围,然后答案就是 ans - (i - l[i]) * (r[i] - i) 就可以了
注意两点
1. 更新的时候32位的每一位都要跟着数的更新而更新
2. 在第一遍更新的时候要用一个 map 去解决可能出现数字重复的问题。

细节看代码 很短 很好懂

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cmath>#include <map>#define ll long longusing namespace std;const int maxn = 2e5 + 10;ll n;int pos[33] = {0};ll ans = 0;int a[maxn] = {0};map <int,int> mp;int l[maxn] = {0};int r[maxn] = {0};int main () {    ios_base :: sync_with_stdio(false);    cin >> n;    ans = (n + 1) * n / 2;    for (int i = 1; i <= n; ++ i) {        cin >> a[i];    }    for (int i = 1;i <= n; ++ i) {        l[i] = mp[a[i]];        for (int j = 0;j < 32; ++ j) {            if (!(a[i] & (1 << j))) {                l[i] = max (l[i],pos[j]);            }        }        for (int j = 0;j < 32; ++ j) {            if (a[i] & (1 << j)) {                pos[j] = i;            }        }        mp[a[i]] = i;    }    for (int i = 0;i < 32; ++ i) pos[i] = n + 1;    for (int i = n; i; -- i) {        r[i] = n + 1;        for (int j = 0;j < 32; ++ j) {            if (!(a[i] & (1 << j))) {                r[i] = min (pos[j],r[i]);            }        }        for (int j = 0;j < 32; ++ j) {            if (a[i] & (1 << j)) {                pos[j] = i;            }        }        ans -= (ll)(i - l[i]) * (ll)(r[i] - i);    }    cout << ans << endl;    return 0;}
阅读全文
0 0
原创粉丝点击