【51Nod 1674】【算法马拉松 19A】区间的价值 V2

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1674
对区间分治,统计\([l,r]\)中经过mid的区间的答案。
我的做法是从mid向右扫到r,统计出所有\([mid,i],mid\leq i \leq r\)的and和or值。
然后发现这些and和or值有很多相同的,把相同的压在一起并记录sum,再从mid-1扫到l并暴力从mid向右统计答案。
事实上因为\([mid,i],mid\leq i \leq r\)是连续的,所以压完后的个数是\(O(2loga)\)的(a为\(10^9\))。
这样时间复杂度是\(O(nlognloga)\)
听说有\(O(nlog^2a)\)的二进制分组做法,好神啊orz

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int in() {
    int k = 0; char c = getchar();
    for (; c < '0' || c > '9'; c = getchar());
    for (; c >= '0' && c <= '9'; c = getchar())
        k = k * 10 + c - 48;
    return k;
}

const int N = 100003;
const ll p = 1000000007;
int n, a[N], AD[N], OR[N], len, sum[N], anow, onow;
ll ans = 0;

void solve(int l, int r) {
    if (l == r) return;
    int mid = (l + r + 1) >> 1;
    
    len = mid;
    AD[len] = OR[len] = a[mid];
    sum[len] = 1;
    for (int i = mid + 1; i <= r; ++i)
        if (((AD[len] & a[i]) != AD[len]) || ((OR[len] | a[i]) != OR[len])) {
            ++len;
            AD[len] = AD[len - 1] & a[i];
            OR[len] = OR[len - 1] | a[i];
            sum[len] = 1;
        } else
            ++sum[len];
    
    anow = onow = a[mid - 1];
    for (int i = mid - 1; i >= l; --i) {
        anow &= a[i];
        onow |= a[i];
        for (int j = mid; j <= len; ++j)
            ans = (ans + (ll) (anow & AD[j]) * (ll) (onow | OR[j]) % p * (ll) (sum[j]) % p) % p;
    }
    
    solve(l, mid - 1); solve(mid, r);
}

int main() {
    n = in();
    for (int i = 1; i <= n; ++i)
        a[i] = in(), ans = (ans + 1ll * a[i] * a[i]) % p;
    
    solve(1, n);
    printf("%d\n", (int) ans);
    return 0;
}

转载于:https://www.cnblogs.com/abclzr/p/6016894.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值