[bzoj 2460]线性基+贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2460

网上很多题目都没说这个题目的证明,只说了贪心策略,我比较愚钝,在大神眼里的显然的策略还是想证明一下才安心……所以这里记录一下证明过程。

贪心策略:按魔力值从大到小排序,从大往小往线性基里插,如果成功插入新元素,就选这个,如果插不进去,就不选这个。

证明:

  设有n个材料,每个材料的属性值是x[1],x[2],...,x[n],魔力值是v[1],v[2],...,v[n],这里假设v已经排好序,即v[1]>=v[2]>=v[3]>=...>=v[n]。

  首先证,一定有一个最优解,包含材料1,其属性值是x[1],魔力值是v[1]。

    假设原问题存在一个最优解 S = { t1, t2, ... , tk }。其中ti代表第ti个物品,且t1<t2<...<tk。

      如果t1等于1,那么得证。

      如果t1不等于1,那么我们来证一定有一个元素可以被1替换下来。

        考虑1为何不能加进S。因为S是线性无关的,加入1以后,S∪{1}就变得线性相关了。所以必然存在S的一个子集,它们的异或和等于x[1]。

        用表达式写出来也就是

(1)

        那么1可以把谁替换下来呢?答案是1可以把任何一个替换下来。我们不妨让它替换下来ti,把式子变一下形,两边同时异或上x[ti]^x[1],就得到了

(2)

        就会发现x[ti]已经可以被线性表示出来了,而且显然,如果不加x[1]肯定是无法线性表示出来x[ti]的(因为S是线性无关的),所以替换后的线性基跟原来是等价的。

        如果不放心,我可以再重述一遍,对于原来S可以表示出来的,替换后的一定也可以表示出来,因为被替换掉的x[ti]已经可以表示出来了;对于原来S不能表示出来的,替换后的也一定表示不出来。可以用反证法证。假设有一个y,用原来的表示不出来,而用替换后的可以表示出来。那肯定是因为加入了x[1]的原因。用式子写出来就是:

(3)

        把x[1]用(1)式代换,就可以得到:

(4)

        是不是担心,万一左边的x都抵消没了怎么办?实际上不会出现这种情况,因为ti就是独一无二的,在x[i]^...^x[j]里是不会有的(因为ti已经被1替换下来了)。这样,就得到了原来的基也可以得到y,与假设矛盾。

  所以这一步证明的作用是什么呢?就是证明了,第一步的贪心策略是正确的。下面来证明,如果第一步的贪心是正确的,以后的贪心也是正确的。

  现在只需证,假设当前已经按照贪心策略造出了一个线性无关的基S = { t1, t2, ... , tk },一定存在一个最优解,包含下一步选择的那个最大魔力值的跟S线性无关的一个材料。

  设下一步的贪心策略选择是j,假设最优解是 G = {t1, t2, ... , tk , tk+1, tk+2, ... , tk+m}。

    如果j∈G,那么得证。

    如果j?G,现在证j一定可以替换掉G中的某个元素,实际上j可以替换掉y1,y2,...ym里的任何一个元素,证明方法跟第一步类似。

      j为什么不能属于G呢?因为G是线性无关的,但是加入j之后,就线性相关了,也就是说j是多余的,j可以用其他的线性表示出来。那么可以得到的式子就是:

(5)

    这个式子实际上跟(1)式是一模一样的。而且这里的i肯定>k,因为根据已知的策略,j一定会选跟t1...tk线性无关的最前面的那个。那么到此,后面的证明跟第1步的证明也是类似的,j也可以替换掉任何一个ti (i>k)。

  综上,问题得证。

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int maxn=1005;
pair<int,ll> a[maxn];

vector<ll> base;
bool add(ll x)
{
    for(int i=0;i<base.size();i++)
        x=min(x,x^base[i]);
    if (x) base.push_back(x);
    if (x) return true;
    else return false;
}

int main()
{
    int n;
    scanf("%d",&n);
    for (int i=0;i<n;i++) scanf("%lld%d",&a[i].second,&a[i].first);
    sort(a,a+n);
    int ans=0;
    for (int i=n-1;i>=0;i--) if (add(a[i].second)) ans+=a[i].first;
    printf("%d",ans);
    return 0;
}
时间: 2024-10-16 22:21:51

[bzoj 2460]线性基+贪心的相关文章

BZOJ 2460: [BeiJing2011]元素 贪心,线性基

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2460 解法:从大到小排序,依次贪心的添加到当前集合就可以了,需要动态维护线性基.用拟阵证明,线性基性质,线性基中任意子集异或和不为0,所以从大到小加入就好. #include <bits/stdc++.h> using namespace std; typedef long long LL; struct node{ LL a, b; node(){} bool operator<

bzoj 2460: [BeiJing2011]元素【线性基+贪心】

先按魔力值从大到小排序,然后从大到小插入线性基中,如果插入成功就加上这个魔力值 因为线性基里是没有异或和为0的集合的,所以正确性显然,然后最优性,考虑放进去一个原来没选的,这样为了可行性就要删掉一个,又因为是从大到小加进去的,所以删掉的这个魔力值一定是大于加进去的,所以不优,所以贪心构造的就是最优解 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int

bzoj 2115 Xor - 线性基 - 贪心

题目传送门 这是个通往vjudge的虫洞 这是个通往bzoj的虫洞 题目大意 问点$1$到点$n$的最大异或路径. 因为重复走一条边后,它的贡献会被消去.所以这条路径中有贡献的边可以看成是一条$1$到$n$的简单路径加上若干个环. 因此可以找任意一条路径,然后找出所有环扔进线性基跑出最大异或和. 但是找出所有环可能会T掉,但是仔细画图发现,并不需要找出所有环,例如: 在上图中,你并不需找出所有的环,只用找出1 - 3 - 4 - 2和3 - 5 - 6 - 4这两个环,它们异或后就能得到环1 -

【BZOJ-2460&amp;3105】元素&amp;新Nim游戏 动态维护线性基 + 贪心

3105: [cqoi2013]新Nim游戏 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 839  Solved: 490[Submit][Status][Discuss] Description 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从超过一堆火柴中拿.拿走最后一根火柴的游戏者胜利. 本题的游戏

【bzoj2460】【beijing2011】【元素】【线性基+贪心】

Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔 法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力取决于使用的矿石. 一般地,矿石越多则法力越强,但物极必反:有时,人们为了获取更强的法力而 使用了很多矿石,却在炼制过程中发现魔法矿石全部消失了,从而无法炼制 出法杖,这个现象被称为"魔法抵消" .特别地,如果在炼制过程中使用超过 一块同一种矿石,那么一定会发生"魔法抵消". 后来,随着人们认知水平的提高,这个

【bzoj3105】【cqoi2013】【新Nim游戏】【线性基+贪心】

Description 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从超过一堆火柴中拿.拿走最后一根火柴的游戏者胜利. 本题的游戏稍微有些不同:在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴.可以一堆都不拿,但不可以全部拿走.第二回合也一样,第二个游戏者也有这样一次机会.从第三个回合(又轮到第一个游戏者)开始,规则和Nim游戏一样. 如果你先拿

Codeforces 1100F(线性基+贪心)

题目链接 题意 给定序列,$q(1\leq q \leq 100000) $次询问,每次查询给定区间内的最大异或子集. 思路 涉及到最大异或子集肯定从线性基角度入手.将询问按右端点排序后离线处理询问,对线性基的每一位贪心的保留靠后的. 代码 #include <bits/stdc++.h> #define DBG(x) cerr << #x << " = " << x << endl; using namespace std;

BZOJ - 2844 线性基

题意:求给定的数在原数组中的异或组合中的排名(非去重) 因为线性基中\(b[j]=1\)表示该位肯定存在,所以给定的数如果含有该位,由严格递增和集合枚举可得,排名必然加上\(2^j\)(不是完全对角就需要额外维护),但这是去重后的结果 可证明的结论是每个数都重复出现了\(2^{n-|B|}\)次 #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include

[bzoj2460] [BeiJing2011]元素(线性基+贪心)

题目大意: 有一些矿石,每个矿石有一个a和一个b值,要求选出一些矿石,b的和最大且不存在某个矿石子集它们的a的异或和为0. 解题关键:对魔力进行由大到小排序,依次加入线性基,统计即可. #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace st