当前位置 : 主页 > 编程语言 > java >

BZOJ 3105([cqoi2013]新Nim游戏-拟阵)

来源:互联网 收集:自由互联 发布时间:2022-10-26
首先先从网上转载一份‘拟阵’的简介: 拟阵 拟阵是满足下列条件的一个序对M=(S,I); 1)S是一个有穷的集合。 2)I是S的一类具有遗传性质的非空子集族。遗传性质定义为:如果B∈I且


首先先从网上转载一份‘拟阵’的简介:

拟阵

拟阵是满足下列条件的一个序对M=(S,I);

1)S是一个有穷的集合。

2)I是S的一类具有遗传性质的非空子集族。遗传性质定义为:如果B∈I且A⊂B,那么A∈I。即若B∈I,则B是S的独立子集(独立子集的定义),且B的任意子集也都是S的独立子集。空集必为I的成员。注意,I是集合的集合。

3)I满足交换性质。交换性质定义为,若A∈I,B∈I且|A|<|B|,则存在某一元素x∈B-A,使得A∪{x}属于I。(这条性质给了我们已知集合B,构造集合A的方法。而性质2暗示了我们已知集合B,找出其子集的性质的办法)

下面是一个拟阵的例子:

无向图G=(V,E)的拟阵,定义为M[G]=(S[G],I[G])。

*集合S[G]定义为E,即G的边集。

*如果A是E的子集,而且A是无回路的,则A属于IG。亦即,一组边A是独立的当且仅当子图G[A]=(V,A)构成了一个森林。

下面证明M[G]是一个拟阵。

1)显然S[G]=E是一个有穷集合。

2)I[G]是遗传的。对于任意的B∈I[G],A⊂B,边集A都∈I[G],原因是从无环的一组边中去掉一些边并不会产生出回路。

3)具有k条边的森林恰好包含|V|-k棵树。若G[A]=(V,A)和G[B]=(V,B)是G的森林,且|B|>|A|,则G[A]中有|V|-|A|棵树,G[B]中有|V|-|B|棵树。由于G[B]中的树比G[A]中的树要少,必有边e(u,v)∈G[B],!∈G[A]而且连接G[A]中的两棵树。将e添加进A,不会产生回路。A∪{e}∈I。

命题得证。

给定拟阵M=(S,I),对于I中的独立子集A∈I,若S有一元素x!∈A,使得将x加入A中仍保持独立性,即A∪{x}∈I,则称x为A的可扩展元素。当拟阵M中的独立子集A没有可扩展元素时,即A不被M中别的独立子集所包含时。称A为极大独立子集。类似于极大线性无关组的证明,所有的极大独立子集具有相同的势。

若对拟阵M=(S,I)中的S指定权函数W,使得对于任意x∈S,有W(x)>0,则称拟阵M为带权拟阵。依此权函数,对于S的子集A有W(A)=Σ(x∈A)W(x)。

适宜用贪心方法获得最优解的许多问题,都可以归结为在加权矩阵中找出一个具有最大权值的独立子集问题。因为任意元素的权值都是正的,故找出的最优子集同时也是最大子集。下面是求带权拟阵最优子集的贪心算法。

GREEDY( M , W )

A<-空集

将S中的元素按照权值W大优先组织成一个优先队列。

While ( S不为空 )

x = GetMax( S ) ;

if ( A ∪ {x} ∈ I)

A = A ∪ {x} ;

return A

这个算法排序的时间为O(NlogN),共判断N次,设判断复杂度为f(N),则整个算法运行时间为O(NlogN+Nf(N))

下面证明算法GREEDY返回的是一个最优子集。

引理1(拟阵具有贪心选择性质)

假设M=(S,I)是一个具有权函数W的加权拟阵,且S被按权值的单调减顺序排列。设x是S的第一个使{x}独立的元素。如果x存在,则存在S的一个包含x的最优子集A

引理2 设M=(S,I)为任意一个拟阵。如果x是S的任意元素,是S的独立子集A的一个可扩展元素,那么x也必然是空集的一个可扩展元素。

推论 设M=(S,i)为任意一个矩阵。如果x不是空集的可扩展元素,那么x也不会是S的任意独立子集A的一个可扩展元素。(这个推论说明了任何元素如果不能被立即用到,则以后也绝不会被用到。所以,在开始时,对S中的那些不是空集的可扩展元素的略过没有漏掉解)

引理3(拟阵具有最优子结构性质)

设x为S中被作用于加权拟阵M=(S,I)的GREEDY算法第一个选择的元素。找一个包含x的具有最大权值的独立子集问题,可以化归为找出加权矩阵M’=(S’,I’)的一个具有最大权值的独立子集问题,此处

S’={y∈S|{x,y}∈I}

I’={B⊂S-{x}|B∪{x}∈I}

其中,M’权函数为受限于S’的M的权函数(即M的由x引起的收缩)。

故可得定理,GREEDY返回最优子集。

首先,开始时被略去的不是空集的元素不予考虑(推论)。一旦选择了第一个元素x,将它加入A是正确的(引理1)。最后,余下的问题就是一个在M的由x引起的收缩M’中寻找一个最优子集问题(引理3)。在过程GREEDY将A置为{x}后,余下的各步骤都可解释为是在拟阵M’=(S’,I’)中进行的。因为B在M’中是独立的,当且仅当B∪{x}在M中是独立的,其中B为任意属于I’的集合。这样,GREEDY的后续操作就会找出M’中的一个具有最大权值的独立子集。而GREEDY的全部操作就可找出M的一个具有最大权值的独立子集。

应用拟阵思想,便可建立了贪心策略的理论基础,还好,终于对贪心有了更新的认识……

那么回到这题,我们的目标是让第二个人取的时候,不存在非空且异或和=0的子集,并让所剩数的和尽量大
设拟阵M={S,I} S为全集,I为不存在非空且异或和=0的子集的集合,
权函数w(x)=x,

然后我们贪心,规则是
每次取出剩下数中最大的那个,观察他是否与之前取的xor线性无关,若成立,则取,取完为止

#include<bits/stdc++.h>
using namespace std;
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
typedef long long ll;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
#define
int n;
ll a[MAXN],b[MAXN]={0};
ll gauss(int n) {
ll ans=0;
For(i,n) {
ll t=a[i];
RepD(j,31) {
if (a[i]>>j&1) {
if (b[j]) a[i]^=b[j];
else {
b[j]=a[i];
break;
}
}
}
if (a[i]) ans+=t;
}
return ans;
}
int main()
{
n=read();
ll tot=0;
For(i,n) tot+= ( a[i]=read() );
sort(a+1,a+1+n);
reverse(a+1,a+1+n);
cout<<tot - gauss(n)<<endl;
return 0;
}


网友评论