NOIP模拟赛 T1签到(线性基)

题目描述

有一个 n × m n\times m n×m的网格,第 i i i行第 j j j列的格子我们记作 ( i , j ) (i,j) (i,j)。每个格子上都有一个数字, ( i , j ) (i,j) (i,j)上的数字为 a i , j a_{i,j} ai,j。你现在在 ( 1 , 1 ) (1,1) (1,1),你想走到 ( n , m ) (n,m) (n,m)处签到,每次你可以走到上下左右四个相邻的格子中的一个,当然,你不能走出网格。你现在的心情值为 a 1 , 1 a_{1,1} a1,1,你的心情飘忽不定,你每走一步,你的心情值就会异或上走到的格子上的数字。你希望你签到的时候心情最好,为此你可以任意绕远路,甚至可以走到签到处的时候暂时不签到。请你求出最大的心情值。

输入格式

第一行两个正整数 n , m n,m n,m

接下来 n n n行,每行 m m m个非负整数,其中第 i i i行第 j j j个整数表示 a i , j a_{i,j} ai,j

输出格式

输出一个整数,表示答案。

输入样例

2 2
1 2
3 4

输出样例

7

数据范围

对于 30 % 30\% 30%的数据, n , m ≤ 4 n,m\leq 4 n,m4
对于另外 30 % 30\% 30%的数据, n , m ≤ 100 , a i , j ≤ 1000 n,m\leq 100,a_{i,j}\leq 1000 n,m100,ai,j1000
对于 100 % 100\% 100%的数据, n , m ≤ 500 , a i , j ≤ 1 0 9 n,m\leq 500,a_{i,j}\leq 10^9 n,m500,ai,j109


题解

前置知识:线性基

首先,因为可以到签到点而不签到,那么沿任意一条路到达签到点后,对于点 ( i , j ) (i,j) (i,j),我们可以沿任意一条路走到点 ( i , j ) (i,j) (i,j),然后原路返回。那么走一次之后,心情值就异或上了 a i , j ⊕ a n , m a_{i,j}\oplus a_{n,m} ai,jan,m

如果我们不考虑 a n , m a_{n,m} an,m,那么其他的 a a a值其实是可以任意选来求异或和的。然后,我们发现选中的点的奇偶性是不变的,而从 ( 1 , 1 ) (1,1) (1,1)走到 ( n , m ) (n,m) (n,m)的路可以确定其奇偶性,那么

  • 如果 n + m n+m n+m是奇数,那么选中的点的个数为偶数
    • 若除了 a n , m a_{n,m} an,m的被选中的点的个数为奇数,那么 a n , m a_{n,m} an,m被选中
    • 若除了 a n , m a_{n,m} an,m的被选中的点的个数为偶数,那么 a n , m a_{n,m} an,m不被选中
  • 如果 n + m n+m n+m是偶数,那么选中的点的个数为奇数
    • 若除了 a n , m a_{n,m} an,m的被选中的点的个数为奇数,那么 a n , m a_{n,m} an,m不被选中
    • 若除了 a n , m a_{n,m} an,m的被选中的点的个数为偶数,那么 a n , m a_{n,m} an,m被选中

我们可以提前将所有不是 a n , m a_{n,m} an,m a i , j a_{i,j} ai,j的值异或上 a n , m a_{n,m} an,m,那么

  • 如果选中的点的个数为偶数,那么答案就是异或和的最大值
  • 如果选中的点的个数为偶数,那么答案就是异或和再异或 a n , m a_{n,m} an,m后的最大值

那怎么求异或和的最大值呢?用线性基即可。

那么如何求异或和再异或 a n , m a_{n,m} an,m后的最大值呢?在线性基中,将 a n s ans ans的初始值设为 a n , m a_{n,m} an,m即可。

时间复杂度为 O ( n m log ⁡ m x ) O(nm\log mx) O(nmlogmx),其中 m x mx mx a i , j a_{i,j} ai,j的最大值。

code

#include<bits/stdc++.h>
using namespace std;
int n,m,ct,lst,ans,a[505][505],b[105],c[500005];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
		}
	}
	lst=a[n][m];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]^=lst;
			c[++ct]=a[i][j];
		}
	}
	--ct;
	for(int i=1;i<=ct;i++){
		for(int j=30;j>=0;j--){
			if((c[i]>>j)&1){
				if(!b[j]){
					b[j]=c[i];break;
				}
				c[i]^=b[j];
			}
		}
	}
	if((n+m)%2==0) ans=lst;
	for(int i=30;i>=0;i--){
		if((ans^b[i])>ans) ans=ans^b[i];
	}
	printf("%d",ans);
	return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个选手有相同的机会和条件进行竞争。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值