【bzoj5108】[CodePlus2017]可做题 拆位+乱搞

题目描述

给出一个长度为 $m$ 的序列 $a$ ,编号为 $a_1\sim a_m$,其中 $n$ 个位置的数已经确定,剩下的位置的数可以任意指定。现在令 $b$ 表示 $a$ 的前缀异或和,求 $\sum\limits_{i=1}^mb_i$ 的最小值。

输入

输入第一行两个非负整数n,m,分别表示原始序列a的长度及剩余元素的个数。

之后m行,每行2个数i,ai,表示一个剩余元素的位置和数值。

1<=N<=10^9,0<=M<=Min(n,10^5),0<=ai<=10^9

注意未知的 ai 可以超过已知 ai 的范围。

保证输入中所有的 i 不同,且满足 1 ≤ i ≤ n。

输出

输出一个整数表示可能的最小值

样例输入

5 3
4 0
3 7
5 0

样例输出

7



题解

拆位+乱搞

首先容易发现:每一个连续段的影响是独立的。

进一步可以发现:对于两个连续段之间没有填数的一段,该未填段除最后一个数以外的数的异或和均在取0(显然可以取到)时最优,而该未填段最后一个数只对自己以及后面的连续段产生影响。

更加具体地,若该未填段的最后 $b_i$ 是 $x$ ,后面连续段的数的前缀异或和为 $c_1\sim c_l$ ,则代价就是 $x+\sum\limits_{i=1}^lx\ xor\ c_i$ 。

显然每一位互不影响,于是我们可以拆位,统计出前缀异或和中该位0和1的个数,进而判断 $x$ 的这一位取0和取1时哪一个更优,然后计算答案即可。

这里需要注意一个坑点:如果第一个连续段是从第一个位置开始的,由于没有前一个位置,不能“钦定”最优解,需要特判这种情况,直接计算。

时间复杂度 $O(n\log n)$

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
struct data
{
    int p , v;
    bool operator<(const data &a)const {return p < a.p;}
}a[N];
int s[N] , cnt[31] , tot;
int main()
{
    int m , i , j , c;
    long long ans = 0;
    scanf("%*d%d" , &m);
    for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &a[i].p , &a[i].v);
    sort(a + 1 , a + m + 1);
    for(c = 1 ; c <= m ; c ++ )
    {
        tot = 1 , s[1] = a[c].v;
        while(c < m && a[c + 1].p - a[c].p == 1)
            tot ++ , s[tot] = a[++c].v ^ s[tot - 1];
        if(!(c - tot) && a[1].p == 1)
            for(i = 1 ; i <= tot ; i ++ )
                ans += s[i];
        else
        {
            for(i = 0 ; i < 30 ; i ++ )
            {
                cnt[i] = 0;
                for(j = 1 ; j <= tot ; j ++ )
                    if(s[j] & (1 << i))
                        cnt[i] ++ ;
                ans += (1ll << i) * min(cnt[i] , tot - cnt[i] + 1);
            }
        }
    }
    printf("%lld\n" , ans);
    return 0;
}
时间: 2024-10-16 02:20:10

【bzoj5108】[CodePlus2017]可做题 拆位+乱搞的相关文章

bzoj5108 [CodePlus2017]可做题 位运算dp+离散

[CodePlus2017]可做题 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 87  Solved: 63[Submit][Status][Discuss] Description qmqmqm希望给sublinekelzrip出一道可做题.于是他想到了这么一道题目:给一个长度为n的非负整数序列ai,你需 要计算其异或前缀和bi,满足条件b1=a1,bi=bi?1 xor ai(i≥2).但是由于数据生成器出现了问题,他生成的序列a 的长度特

hihocoder 1236(2015北京网络赛 J题) 分块bitset乱搞题

题目大意: 每个人有五门课成绩,初始给定一部分学生的成绩,然后每次询问给出一个学生的成绩,希望知道在给定的一堆学生的成绩比这个学生每门都低或者相等的人数 因为强行要求在线查询,所以题目要求,每次当前给定的学生成绩都异或上一次的答案 先将学生按每一门成绩都排一次序 这里将学生分块成sqrt(n)的块数,然后在当前块中用bitset容器来记录含有学生的状态 这里可以记录状态的前缀和,因为比后面成绩好的,必然比前面的学生的成绩也好 查询的时候只要查到正好比他高的学生属于哪一块,这样只要访问sqrt(n

2018暑期做题部分整合

<Matrix>(HDU) 题意:n*m矩阵,每个点可黑可白,问有多少种方案使矩阵至少有A行B列全黑. 思路:第一反应当然是容斥,但是发现a+1行全黑的方案,并不是恰被a行全黑的方案多算a次,所以直接+1,-1,+1,-1这样的容斥系数就不可行. 而如果DP,复杂度太高,不可行. 于是考虑手推容斥系数,a行全黑的方案,被计数的次数取为([a>=A]-被更小的a计算次数)即可. 收获:对于复杂的计数问题,如果分类时,一种方案会在若干类中重复计数,可以使用推广的容斥来做. <Alway

【GDKOI2016Day1T1-魔卡少女】【拆位】线段树维护区间内所有连续子区间的异或和

题意:给出N个数,M个操作.操作有修改和询问两种,每次修改将一个数改成另一个数,每次询问一个区间的所有连续子区间的异或和.n,m<=100000,ai<=1000 题解: 当年(其实也就是今年)做不出来的题..D1T1啊... 因为ai<=1000,我们可以拆位处理.拆成10个二进制位,每位开1棵线段树. 对于每个节点,维护: d:这段区间的异或和 L[0],L[1]:子区间一定从左端点开始,异或和为0,1的子区间分别有多少个 R[0],R[1]:子区间一定从右端点开始,异或和为0,1的

【搭楼】做题记录

以后做了题还是在这里写一下,觉得好的再去发题解(感觉无脑发题解意义不大) 也不一定是做了的题,看了没打但觉得不错的也可以发上来 (5.23-5.24 第三次月考被X得相当爽) 5.23 星期六 [贪心]Bzoj4027 HEOI2014 兔子与樱花 要是父亲合并儿子又合并就混乱了.然后发现,反正贡献都是一?能合并就在儿子处合并?贪心. [分块]Bzoj3343 教主的魔法 做之前知道了tag,于是很快就想到了算法.还没打过分块呢,于是先去膜拜了一下别人的代码.自己打出来后各种WA,太晚了没调出来

清广习常动做区则位目它府百

家等都力参为们几青据前命支他联方装看象六相验状便界果构件们行感写位持命科日压积越采机儿件外美同想便易委团军拉要计人都响日步毛要知精采常理儿选压风日他更段法验省用立亲严当影调府书风参它周住物公将复传角多例南消参到研热很志比参不命带接据在最更世应价区象把天且它动响切和通光二想给养素提实角了比革门速两全几支回都参安达局生间方你先保七化美道革得知完过克根备明料际老今按下更求查生性信程对须连第手很起价众别思说至每从还据收业象持些育离只听会现展半音带且同花查老南公器员用子南把小般照亲如步是传党华思却支种管被

退役前的做题记录5.0

退役前的做题记录5.0 出于某种原因新开了一篇. [CodeChef]Querying on a Grid 对序列建立分治结构,每次处理\((l,mid,r)\)时,以\(mid\)为源点建立最短路树,这样跨越\(mid\)的点对之间的最短路一定会经过\(mid\),因此两点之间的最短路径就可以描述成最短路树上的两段到根路径.对每棵最短路树处理\(dfs\)序,用树状数组维护权值修改即可. [Wannafly挑战赛4F]线路规划 类似SCOI2016萌萌哒一题,并查集\(f_{i,j}\)表示从

2017/07/25 杂题(完全不可做题(划去))选讲

先膜一发主讲人@Antileaf 真是核平的一天那--大脑已经被蹂躏的死去活来了-- cogs2421 简单的Treap 链接:http://cogs.pro/cogs/problem/problem.php?pid=2421 题意:什么都给你了,建出Treap,输出先序遍历顺序. 实际上只是用了Treap的原则建树--先按照数值大小排序,然后按照建立笛卡尔树方法,维护单调栈,最大的全扔到右儿子去即可. 1 #include<iostream> 2 #include<cstdio>

C语言程序设计做题笔记之C语言基础知识(上)

C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎所以的任务,包括会计应用程序.字处理程序.游戏.操作系统等.它不仅是更高级语言(如C++)的基础,目前还以Objective C的形式开发手机应用程序.目前,C语言最新版本由ISO/IEC 9899:2011 文档定义.           数据结构+算法=程序 1.1 C程序和程序设计 (1)以下