[校内模拟]Invert

18 篇文章 0 订阅
14 篇文章 0 订阅

Description

在一个n*n的棋盘上,每个格子要么是黑色,要么是白色
有两个人在博弈,每次操作者可以选择一个白色格子,和一个不超过k的正整数a,然后将以这个格子为右下角的边长为a的正方形反色,需要保证这个正方形不越界,无法操作者输
问先手是否必胜
白色的格子为给出的m个矩形的并
k,n<=1e9,m<=5e5

Solution

考虑另一个游戏,每个格子有若干个koishi,每次操作可以选择一个koishi拿掉,然后将这个正方形内其他格子放上一个koishi
容易发现胜负只和某个格子内的koishi的奇偶性有关,这个和原问题是等价的
考虑每个koishi是独立的,我们只需要计算出Sg(i,j)表示koishi在点(i,j)的状态
打表发现Sg(i,j)=min(lowbit(i),lowbit(j),lim),其中lim是最大小于k的2的幂
证明可以归纳
然后考虑扫描线+线段树,我们在线段树上维护被覆盖的y的lowbit(y)=i的奇偶性,这可以写成一个30位二进制数
考虑记lowbit(y)>=i,那么可以发现一个被覆盖的区间[l,r]的二进制数就是r^(l-1)
用标记永久化的线段树维护即可
复杂度O(m log n)

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

int read() {
	char ch;
	for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
	int x=ch-'0';
	for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x;
}

const int N=1e6+5;

int n,m,k,c,tot,pl,pr,pz;

struct L{int x,l,r,opt;}a[N];
bool cmp(L a,L b) {return a.x<b.x;}

int tr[N*15],cnt[N*15],ls[N*15],rs[N*15],rt,tmp;

void modify(int &v,int l,int r) {
	if (!v) v=++tmp;
	if (pl<=l&&r<=pr) {
		cnt[v]+=pz;
		tr[v]=cnt[v]?(r^(l-1)):(tr[ls[v]]^tr[rs[v]]);
		return;
	}
	int mid=l+r>>1;
	if (pl<=mid) modify(ls[v],l,mid);
	if (pr>mid) modify(rs[v],mid+1,r);
	tr[v]=cnt[v]?(r^(l-1)):(tr[ls[v]]^tr[rs[v]]);
}

int main() {
	freopen("invert.in","r",stdin);
	freopen("invert.out","w",stdout);
	n=read();m=read();k=read();
	fo(i,1,m) {
		int ax=read(),ay=read(),bx=read(),by=read();
		a[++tot].x=ax;a[tot].l=ay;a[tot].r=by;a[tot].opt=1;
		a[++tot].x=bx+1;a[tot].l=ay;a[tot].r=by;a[tot].opt=-1;
	}
	sort(a+1,a+tot+1,cmp);
	int la=1,nim=0;
	for(int l=1,r=0;l<=tot;l=r+1) {
		while (r<tot&&a[r+1].x==a[l].x) r++;
		nim^=((la-1)^(a[l].x-1))&tr[1];
		fo(i,l,r) {
			pl=a[i].l;pr=a[i].r;pz=a[i].opt;
			modify(rt,1,n);
		}
		la=a[l].x;
	}
	for(c=1;c<=k;c<<=1);
	puts(nim&(c-1)?"Gator":"Alligator");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值