首页 > 其他 > 详细

bzoj5092 分割序列

时间:2019-12-18 00:19:12      阅读:87      评论:0      收藏:0      [点我收藏+]

题目链接

problem

对于一个长度为n的非负整数序列\(b_1,b_2,...,b_n\),定义这个序列的能量为:\(f(b)=\max\limits_{i=0,1,...,n}(b_1 \otimes b _2 \otimes...\otimes b_i)+(b_{i+1} \otimes b_{i+2} \otimes...\otimes b_n)\),给定一个长度为n的非
负整数序列\(a_1,a_2,...,a_n\),请计算a的每个前缀的能量值。

solution

先对a求一边前缀异或和。然后对于前i个元素,从j位置分开的贡献就是\(S_i\otimes S_j+S_j\)

从高到低按位处理。如果\(S_i\)的第k位为1,那么无论\(S_j\)的第k位为0还是为1,造成的贡献都是\(2^k\)。如果\(S_i\)的第k位为0,那么如果在满足前面位置的限制的情况下,\(S_j\)的第k位可以为1,那么造成的贡献就是\(2\times 2^k\)

那么问题来了,当\(S_i\)的第k位为0时,如何判断前面是否有某个位置在满足前面限制的情况下当前位置为1呢?

\(f_i\)表示i的超集出现的最靠前的位置。然后上面的判断就很好做了:只要看一下满足所有限制的最小位置是不是在i之前就可以了。

因为是超集,所以\(f_i\)的预处理可以用\(FMT\)优化。复杂度\(\Theta(2^kk)\)

总复杂度就是\(\Theta(nk+2^kk)\)

code

/*
* @Author: wxyww
* @Date:   2019-12-17 22:04:49
* @Last Modified time: 2019-12-17 22:18:24
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 300100;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1; c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0'; c = getchar();
    }
    return x * f;
}
int mi[N],mx,f[N * 10],a[N];
int main() {
    int n = read();
    
    memset(f,0x3f,sizeof(f));

    for(int i = 1;i <= n;++i) {
        a[i] = read() ^ a[i - 1];f[a[i]] = min(i,f[a[i]]);
        mx = max(mx,a[i]);
    }

    mi[0] = 1;
    for(int i = 1;i <= 30;++i) mi[i] = mi[i - 1] << 1;

    for(int i = 0;i <= 20;++i) {
        for(int j = 0;j <= mx;++j) {
            if(!(j >> i & 1)) f[j] = min(f[j],f[j | (1 << i)]);
        }
    }

    for(int i = 1;i <= n;++i) {
        int now = 0;
        ll ans = 0;
        for(int k = 20;k >= 0;--k) {
            if((a[i] >> k) & 1) ans += mi[k];
            else if(f[now | (1 << k)] <= i) {
                ans += 2ll * mi[k],now |= (1 << k);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

bzoj5092 分割序列

原文:https://www.cnblogs.com/wxyww/p/bzoj5092.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!