zoukankan      html  css  js  c++  java
  • 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]<=10^18)。

    Output

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

    Sample Input

    3 2
    1 5 7

    Sample Output

    3

    HINT

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

    Solution

    有点鬼畜的贪心……其实也不算难……

    我们从高到低位枚举答案,$check$一下答案这一位是否能够为$0$。因为是按位贪心,所以肯定是高位能填$0$优先填$0$然后再考虑后面。接下来问题就在于$check$怎么写了。

    很显然对于前面答案选了$0$的位置,会在我们后面$check$的时候产生一定限制,我们把它存到一个变量$lim$里面。前面答案选了$1$的位置我们可以把它直接算到变量$ans$里面。

    $check$的时候,从头到尾开始扫,一个一个往里加数异或起来。直到加到满足前面的限制而且也满足当前贪心位为$0$的时候,就可以把这一段拿出来了。如果最后能完整的拿出大于等于$m$段的话就$return~true$,否则$return~false$。

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #define N (500009)
     4 #define LL long long
     5 using namespace std;
     6 
     7 LL n,m,ans,lim,a[N];
     8 
     9 bool check(int x)
    10 {
    11     LL now=0,cnt=0;
    12     for (int i=1; i<=n; ++i)
    13     {
    14         now^=a[i];
    15         if (!(now&lim) && !(now&(1ll<<x-1))) now=0, ++cnt;
    16     }
    17     return (cnt>=m && !now);
    18 }
    19 
    20 int main()
    21 {
    22     scanf("%lld%lld",&n,&m);
    23     for (int i=1; i<=n; ++i)
    24         scanf("%lld",&a[i]);
    25     for (int i=64; i>=1; --i)
    26         if (!check(i)) ans|=(1ll<<i-1);
    27         else lim|=(1ll<<i-1);
    28     printf("%lld
    ",ans);
    29 }
  • 相关阅读:
    Kinect 开发 —— 硬件设备解剖
    Kinect 开发 —— 引言
    (转)OpenCV 基本知识框架
    OpenCV —— 摄像机模型与标定
    OpenCV —— 跟踪与运动
    OpenCV —— 图像局部与分割(二)
    OpenCV —— 图像局部与部分分割(一)
    OpenCV —— 轮廓
    OpenCV —— 直方图与匹配
    OpenCV —— 图像变换
  • 原文地址:https://www.cnblogs.com/refun/p/10211322.html
Copyright © 2011-2022 走看看