牛客OI周赛11-提高组 - A 矩形异或 - 打表找规律

链接:https://ac.nowcoder.com/acm/contest/941/A
来源:牛客网

题目描述
Pi 有一个 n * n 的表格
第 x 行第 y 列写着正整数 x+y-1
m 次询问,每次给出 xl, yl, xr, yr
求第 xl 行到第 xr 行中第 yl 列到第 yr 列这 (xr-xl+1)*(yr-yl+1) 个正整数的异或和

输入描述:
第一行两个正整数 n, m
接下来 m 行每行四个正整数依次为 xl, yl, xr, yr
保证 1≤xl≤xr≤n, 1≤yl≤yr≤n
输出描述:
m 行
每行一个正整数为所求的异或和
示例1
输入
3 1
1 2 2 3
输出
6
说明
(2 ^ 3 ^ 3 ^ 4)==6
备注:
50%
n≤1000,
m≤10000
70%
n≤1000000,
m≤20000
100%
n≤10^9,
m≤2∗10^5
解题思路:
先求出(1,1) 到(x,y)矩阵元素异或和,用容斥可得答案;
方便起见x 找一下规律发现:
if x & 1:
(Σ(x+1, y-1): i ++i) ^ (Σ(1, x): i i+=2) ^ (Σ(y, x+y-1): i i+=2)
else:
(Σ(1, x-1): i i+=2) ^ (Σ(y+1, x+y-1): i i+=2)

至于连续数字或连续奇数的异或和也是找规律发现与 %4有关

代码:

#include
using namespace std;
typedef long long ll;
namespace io{
	const int SIZE=1e7+10;
	char inbuff[SIZE];
	char *l,*r;
	inline void init(){
		l=inbuff,r=inbuff+fread(inbuff,1,SIZE,stdin);
	}
	inline char gc(){
		if(l==r)init();
		return(l!=r)?*(l++):EOF;
	}
	void read(ll &x){
		x=0;char ch=gc();
		while(!isdigit(ch))ch=gc();
		while(isdigit(ch))x=x*10+(ch^48),ch=gc();
	}
}using io::read;
ll all(ll n){
	ll t=n;
	n%=4;
	if(n==0)return t;
	if(n==1)return 1;
	if(n==2)return t+1;
	return 0;
}
ll odd(ll n){
	ll t=n;
	n=(n+1)%8;
	if(n==0)return 0;
	if(n==2)return t;
	if(n==4)return 2;
	return t+2;
}
ll even(ll n){
	if(n&1)return all(n)^odd(n);
	else return all(n)^odd(n-1);
}
ll lr(ll a,ll b){
	if(a==b)return odd(a+b-1);
	if(a>b)swap(a,b);
	if(a&1){
		ll ans=0,res=0;
		if(b>=a+2)ans=all(b-1)^all(a);
		if(b&1)res=odd(a+b-1)^odd(b-2);
		else res=even(a+b-1)^even(b-2);
		return odd(a)^res^ans;
	}else{
		ll res=0;
		if(b&1)res=even(a+b-1)^even(b-1);
		else res=odd(a+b-1)^odd(b-1);
		return odd(a-1)^res;
	}
}
int main(){
	ll n,m;read(n),read(m);
	while(m--){
		ll a,b,c,d;read(a),read(b),read(c),read(d);
		if(a>c)swap(a,c);
		if(b>d)swap(b,d);
		ll ans=(lr(c,d)^lr(a-1,d)^lr(c,b-1)^lr(a-1,b-1));
		printf("%lld\n",ans);
	}
	return 0;
}

你可能感兴趣的:(ACM_思维贪心,比赛)