zoukankan      html  css  js  c++  java
  • BZOJ5092:[Lydsy1711月赛]分割序列(贪心,高维前缀和)

    Description

    对于一个长度为n的非负整数序列b_1,b_2,...,b_n,定义这个序列的能量为:f(b)=max{i=0,1,...,n}((b_1 xor b_2 xor...xor b_i)+(b_{i+1} xor b_{i+2} xor...xor b_n))其中xor表示按位异或(XOR),给定一个长度为n的非负整数序列a_1,a_2,...,a_n,请计算a的每个前缀的能量值。

    Input

    第一行包含一个正整数n(n<=300000),表示序列a的长度。
    第二行包含n个非负整数a_1,a_2,...,a_n(0<=a_i<=10^6),依次表示a中每个元素的值。

    Output

     包含n行,每行一个整数,即a每个前缀的能量值。

    Sample Input

    5
    1 2 3 4 5

    Sample Output

    1
    3
    6
    10
    9

    Solution

    题意其实就是对数组的异或前缀和$a[i]$,对每个$i$求出最大$a[j]+(a[j]~xor~a[i])$。

    既然是二进制,就考虑按位贪心得出$a[j]$的值。

    假设$a[i]$当前一位为$1$,那么$a[j]$的这一位选$0$或者$1$对答案都是一样的。

    如果$a[i]$当前一位为$0$,那么$a[j]$就这一位填$1$。这一位填了$1$,后面贪每一位的时候必须包含这一位的$1$,也就是超集。这玩意儿用高维前缀和预处理一下最靠前的超集的位置就好了。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (1<<20)
     5 using namespace std;
     6 
     7 int n,a[N],f[N];
     8 
     9 int main()
    10 {
    11     memset(f,0x7f,sizeof(f));
    12     scanf("%d",&n);
    13     for (int i=1; i<=n; ++i)
    14     {
    15         scanf("%d",&a[i]);
    16         a[i]^=a[i-1]; f[a[i]]=min(f[a[i]],i);
    17     }
    18     for (int i=0; i<20; ++i)
    19         for (int j=0; j<(1<<20); ++j)
    20             if (!(j&(1<<i))) f[j]=min(f[j],f[j^(1<<i)]);
    21     for (int i=1; i<=n; ++i)
    22     {
    23         int ans=0,now=0;
    24         for (int j=19; j>=0; --j)
    25             if (a[i]&(1<<j)) ans+=(1<<j);
    26             else if (f[now^(1<<j)]<=i) ans+=(1<<j)*2, now^=(1<<j);
    27         printf("%d
    ",ans);
    28     }
    29 }
  • 相关阅读:
    提交上了,却在iTunes Connect没有新版本的任何消息
    真机调试 —— An unknown error occurred.
    UI第二节——UIButton详解
    UI第一节—— UILable
    OC第九节——协议与代理
    补10月26日
    我看互联网第一约战
    接受自己的不完美---写在毕业之后的总结
    写给自己的学习之道
    越过山丘
  • 原文地址:https://www.cnblogs.com/refun/p/10161118.html
Copyright © 2011-2022 走看看