• BZOJ4245 ONTAK2015 OR-XOR 【位运算+贪心】*


    BZOJ4245 ONTAK2015 OR-XOR


    Description

    给定一个长度为n的序列a[1],a[2],…,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or … or c[m]。请求出总费用的最小值。

    Input

    第一行包含两个正整数n,m(1<=m<=n<=500000),分别表示序列的长度和需要划分的段数。
    第一行包含n个整数,其中第i个数为a[i](0<=a[i]<=1018)

    Output

    输出一个整数,即总费用的最小值。

    Sample Input

    3 2
    1 5 7

    Sample Output

    3

    HINT

    第一段为[1],第二段为[5 7],总费用为(1) or (5 xor 7) = 1 or 2 = 3。


    首先肯定是要考虑贪心的
    那么应该如何贪心呢?
    首先我们要最小化异或的值,不难想到按照二进制为来贪心
    然后就可以先把前缀和算出来
    然后对于一个二进制位i
    必须要满足an(1<<i)=0这一个位置才可以变成0
    所以我们就先判断一下,然后找出在1~n中所有的i位是0的位置
    如果这个位置数量大于m,则这一个位可以是0,否则不能
    如果可以为零我们就把所有这一个位置不是0的位置打上标记,以后就不再考虑


    注意位运算也要longlong


     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 500010
     4 #define LL long long
     5 #define id (1ll<<i)
     6 #define fu(a,b,c) for(LL a=b;a<=c;++a)
     7 #define fd(a,b,c) for(LL a=b;a>=c;--a)
     8 LL a[N],n,m;
     9 bool vis[N]={0};
    10 int main(){
    11   scanf("%lld%lld",&n,&m);
    12   fu(i,1,n)scanf("%lld",&a[i]),a[i]^=a[i-1];
    13   LL ans=0;
    14   fd(i,63,0){
    15     if(a[n]&id){ans|=id;continue;}
    16     int siz=0;
    17     fu(j,1,n)if(!vis[j]&&!(a[j]&id))siz++;
    18     if(siz<m)ans|=id;
    19     else fu(j,1,n)if(a[j]&id)vis[j]=1;
    20   }
    21   printf("%lld",ans);
    22   return 0;
    23 }
  • 相关阅读:
    HDU2059(龟兔赛跑)
    pat 1012 The Best Rank
    pat 1010 Radix
    pat 1007 Maximum Subsequence Sum
    pat 1005 Sign In and Sign Out
    pat 1005 Spell It Right
    pat 1004 Counting Leaves
    1003 Emergency
    第7章 输入/输出系统
    第六章 总线
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676248.html
Copyright © 2020-2023  润新知