zoukankan      html  css  js  c++  java
  • BZOJ:5092 [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

    题意:对数组的异或前缀和a[i],对于每个i,求最大a[j]+a[j]^a[i];

    思路:从高位到第位贪心(20->0),如果第i位为1,显然无论选0或者1够有一样的贡献。如果为0,我们优先选1;这次选了1后,后面选的应该包括这个1,即之前选的1的集合的超集。    我们用高维前缀和来求每个数的超集的最小位置。如果最小位置小于等于i,说明这意味可以选1。

    (这个公式还可以求最小位置ORZ。

    (总觉得再CF做过类似的题,而且当时没做来

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1<<20;
    int a[maxn],f[maxn];
    int main()
    {
        memset(f,127,sizeof(f));
        int N; scanf("%d",&N);
        for(int i=1;i<=N;i++){
            scanf("%d",&a[i]);
            a[i]^=a[i-1];
            f[a[i]]=min(f[a[i]],i);
        }
        for(int i=0;i<20;i++){
            for(int j=0;j<(1<<20);j++)
              if(!(j&(1<<i))) f[j]=min(f[j],f[j|(1<<i)]);
        }
        for(int i=1;i<=N;i++){
            int ans=0,now=0;
            for(int j=19;j>=0;j--){
                if((a[i]>>j)&1) ans+=(1<<j);
                else if(f[now|(1<<j)]<=i) ans+=(1<<j)*2,now|=(1<<j);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    C++中rand()函数的用法
    oracle用户操作
    oracle日期操作
    PLS-00157: AUTHID only allowed on schema-level programs解决办法 包体的过程使用调用者权限方法
    oracle表空间中PCTFREE, PCTUSED, INITRANS, MAXTRANX参数的解释
    证券从业人员考试
    Oracle连接远程数据库的四种设置方法
    [中英對照] Steve Jobs 對美國史丹福大學畢業生演講全文
    myeclipse之完全破解
    JDK配置之坑
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9948668.html
Copyright © 2011-2022 走看看