题解
思维题
一开始觉得比较像最大XOR路径
但是这里是点权
考虑到是网格图,我们就可以来研究一下它的性质
如果从1,1出发,随意地走一条路径,再按原路返回
发现我们最后的贡献就是任意一个格子
换句话说,我们每走一步,都可以选择任意一个格子的权值,异或到答案上
因为两次可以选同样的值,所以我们选出来的格子数一定是与n+m-1同奇偶的
问题就可以转化为:给出一个数组,选出奇数/偶数个数,使它们的异或和最大
我们可以把(奇数个数的异或和)拆成(偶数个数异或和^某一个数)
于是我们就来解决偶数个数异或起来最大的最大值
我们很显然,可以把所有的数两两异或算出来
但是这样做肯定会超时
于是我们想到了随机化
随机两个数,把他们的异或和加入线性基
应该就可以AC了
哦哦,还有一个优化,先把所有的数排一个序,先把最小的数依次异或上每一个数的值加入线性基
因为最小的数对于其它值的影响是最小的,所以这么一来,线性基就基本上被填满了
然后random_shuffle一下,用n^2来把所有的两两异或的值加入线性基,当线性基满了就break
大功告成!!!
以上就是我考试时的思路,然后我把它写了出来,信心满满想要AC
然后考完一看
啊啊啊啊啊啊,为什么只有30pts
一看代码
用最小值异或其他值的范围只开了n,本来应该是n*m的
把范围改大,测了一下
还是30pts
啊啊啊啊啊啊,怎么办怎么办怎么办
Oh,还有这一手,换一种随机方式,保证可以AC
于是把random_shuffle后的n^2改成了O(n)扫一遍过去,把相邻两个数的异或值加入线性基
再测一下
A C 了
啊啊啊啊啊啊,没切掉签到题,好难受,啊啊啊啊啊啊
看了一下题解
发现比我的想法更巧妙
哪里用得着随机化啊。。。
唉,智商余额不足啊
但是随机化写起来简单一些吧(e,应该是好想一些)
我的代码:(随机化+线性基)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 505
int a[N][N],b[N*N];
int base[33],siz,len;
void add(int x)
{
for(int i=len-1;i>=0;i--)if((x>>i)&1){
if(!base[i]){base[i]=x;siz++;return;}
x^=base[i];
}
}
int query(int x)
{
for(int i=len-1;i>=0;i--)
x=max(x,x^base[i]);
return x;
}
int main()
{
freopen("sign.in","r",stdin);
freopen("sign.out","w",stdout);
int n,m,i,j,mx=0;
n=gi();m=gi();
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
b[(i-1)*m+j]=a[i][j]=gi();
mx=max(mx,a[i][j]);
}
while(mx)len++,mx>>=1;
sort(b+1,b+n*m+1);
for(i=1;i<=n*m;i++)add(b[1]^b[n]);
random_shuffle(b+1,b+n*m+1);
for(i=1;i<n*m&&siz<len;i++)
add(b[i]^b[i+1]);
if((n+m-1)&1){
int ans=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
ans=max(ans,query(a[i][j]));
printf("%d",ans);
}
else printf("%d",query(0));
}
std:(巧妙的线性基)(好短的代码)
#include<cstdio>
#define K 30
int b[K+1];
int main()
{
freopen("sign.in","r",stdin);
freopen("sign.out","w",stdout);
int n,m,x,i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n*m;++i)
{
scanf("%d",&x);x|=1<<K;
for(j=K;~j;--j)if(x&(1<<j))x^=b[j]=b[j]?b[j]:x;
}
for(x=((n+m)&1)<<(j=K);~j;--j)if(~x&(1<<j))x^=b[j];
printf("%d",x&((1<<K)-1));
}
唉,老年选手的日常爆炸