• 51NOD 区间的价值 V2


    http://www.51nod.com/contest/problem.html#!problemId=1674

    因为题目要求的只是& 和 |

    这两个运算。而这两个运算产生的值是有限的。

    &,当产生的值是0的时候,就不会再变化了。

    |,当产生的值是(111111111)的时候,值也不变化了。

    所以每种运算的状态数也就30种不同的情况。

    所以考虑分治,

    先算出[mid + 1, R]中的值,就是固定mid + 1,一直向右边&和|

    然后在[mid, L]从mid开始一直向左边&和|,这样的话,如果已经得到了右半区间的各种情况,就可以快速算出整个区间的情况。

    把and起来得值和or起来得值进行统计,因为每种运算只有30种情况,所以当他们都一样的时候,就压缩在一起,统计有多少个不同的值即可。

    30 + 30 = 60

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 100000 + 20;
    LL a[maxn];
    LL ans;
    const int MOD = 1000000007;
    const LL one = 1;
    int AND[900 + 2], OR[900 + 2]; //全部是0或者全部是1后,状态不会变了
    int sum[900 + 2]; //所以两种状态相同的时候,也就900种状态
    void calc(int L, int R) {
        if (L == R) {
            ans = (ans + a[L] * a[L] % MOD) % MOD;
            return;
        }
        int mid = (L + R) >> 1;
        int len = 1;
        AND[len] = OR[len] = a[mid + 1];
        sum[len] = 1;
        for (int i = mid + 2; i <= R; ++i) {
            if ((AND[len] & a[i]) == AND[len] && (OR[len] | a[i]) == OR[len]) {
                sum[len]++;
            } else {
                ++len;
                AND[len] = AND[len - 1] & a[i];
                OR[len] = OR[len - 1] | a[i];
                sum[len] = 1;
            }
        }
        LL nowAnd = (one << 31) - 1;
        LL nowOr = 0;
        for (int i = mid; i >= L; --i) {
            nowAnd = nowAnd & a[i];
            nowOr |= a[i];
            for (int j = 1; j <= len; ++j) {
    
                ans += (nowAnd & AND[j]) * (nowOr | OR[j]) % MOD * sum[j] % MOD;
                ans %= MOD;
            }
        }
        calc(L, mid);
        calc(mid + 1, R);
    }
    void work() {
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
        calc(1, n);
        cout << ans << endl;
    }
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        IOS;
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    display:inline、block、inline-block的区别
    CSS选择器优先级总结
    bootstarp模板01
    Vue深度学习(6)- 组件
    在Ubuntu下安装mongodb
    Ajax高级应用---Comet
    ubuntu安装
    linux使用
    跨浏览器的CORS
    防止伪造跨站请求
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6017544.html
Copyright © 2020-2023  润新知