題解
思維題
一開始覺得比較像最大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));
}
唉,老年選手的日常爆炸