• [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

    毒瘤题

    做法:贪心

    我们要结果尽可能小,那么就要尽可能地让高位为0

    先处理出前缀异或和,然后从高位往低位枚举,看看能否让这一位为0(即在前缀异或和中存在m个该位可以为0的,且总异或和这位也不为0)

    然后如果能为0的话,就把前缀异或和中的所有不为0的位数标记一下,之后都不能再选了(如果选了可能你这一位就变成了1,然后高位为0显然比低位为0更优)

    就这样去贪心就可以了

    这题真的好神啊。。不看题解完全不会写

    #include <bits/stdc++.h>
    
    using namespace std ;
    
    #define ll long long
    #define N 500010
    
    int n , m ;
    ll a[ N ] , c[ N ] , ans = 0 ;
    bool vis[ N ] ;
     
    int main() {
        scanf( "%d%d" , &n , &m ) ;
        for( int i = 1 ; i <= n ; i ++ ) {
            scanf( "%lld" , &a[ i ] ) ;
            c[ i ] = c[ i - 1 ] ^ a[ i ] ;
        }    
        for( int i = 62 ; i >= 0 ; i -- ) {
            int cnt = 0 ;
            for( int j = 1 ; j <= n ; j ++ ) {
                if( !vis[ j ] && ( c[ j ] & ( 1ll << i ) ) == 0 ) cnt ++ ;
            }
            if( cnt >= m && ( c[ n ] & ( 1ll << i ) ) == 0 ) {
                for( int j = 1 ; j <= n ; j ++ ) {
                    if( ( c[ j ] & ( 1ll << i ) ) != 0 ) vis[ j ] = 1 ;
                }
            }else ans = ans | ( 1ll << i ) ;
        }
        printf( "%lld
    " ,  ans ) ;
        return 0 ;
    } 
  • 相关阅读:
    python爬虫学习之MongoDB学习笔记
    python基础学习笔记
    基于python的turtle模块画国旗
    基于tkinter的gui编程基础学习笔记
    python爬虫实现各视频网站vip付费电影下载
    网页模板收藏
    python爬虫实战项目
    python爬取詹姆斯职业生涯数据并生成图标展示
    爬虫框架scrapy学习笔记
    基于python的OpenCV图像处理学习笔记
  • 原文地址:https://www.cnblogs.com/henry-1202/p/BZOJ4245.html
Copyright © 2020-2023  润新知