首页 > 其他 > 详细

【CF1511G】Chips on a Board

时间:2021-04-30 20:52:21      阅读:25      评论:0      收藏:0      [点我收藏+]

题目

题目链接:https://codeforces.com/problemset/problem/1511/G
一个 \(n\times m\) 的棋盘,每一行有且仅有一个石子,第 \(i\) 行的石子在第 \(a_i\) 列。
每次询问给出 \(l,r\),求把棋盘第 \(1\sim l-1\) 列和第 \(r+1\sim n\) 列直接删去(包括在这些列上的石子)后,剩余石子进行 NIM 游戏(每次选择一行的石子往左移动若干格,不能动者败),先手是否必胜。
\(n,m,Q\leq 2\times 10^5\)

思路

其实转化一下就是求

\[\oplus ^{n}_{i=1}[l\leq a_i\leq r](a_i-l) \]

\(f[i][j]\) 表示满足 \(i\leq a_k< i+2^j\) 的所有石子,以 \(i\) 为左边界进行 NIM 博弈,得到的异或和。
考虑倍增求出 \(f\)。我们发现,在合并两个长度为 \(2^{j-1}\) 的块时,前半部分的贡献不变,后半部分的每一个石子的贡献都增加了 \(2^{j-1}\)。也就是如果后半部分的石子数量有奇数个,则会对异或和产生 \(2^{j-1}\) 的贡献,不然不会对 二进制下 \(j-1\) 这一位造成贡献。
然后考虑询问。我们从大到小枚举块长,如果这个块长可以被加入,那么除了这一块的贡献以外,还会对后面的,还没有被加入的位置产生二进制下仅一位的贡献。所以我们也只需要判断还没被加入的部分的石子数量是否是奇数个即可。
时间复杂度 \(O((Q+m)\log m+n)\),吊打官方题解(

代码

#include <bits/stdc++.h>
using namespace std;

const int N=200010,LG=18;
int n,m,cnt[N],f[N][LG+1];

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1,x;i<=n;i++)
	{
		scanf("%d",&x);
		cnt[x]++; f[x-1][1]^=1;
	}
	for (int i=1;i<=m;i++)
		cnt[i]+=cnt[i-1];
	for (int i=m;i>=1;i--)
		for (int j=2;i+(1<<j)-1<=m;j++)
		{
			f[i][j]=f[i][j-1]^f[i+(1<<j-1)][j-1];
			if ((cnt[i+(1<<j)-1]-cnt[i+(1<<j-1)-1])&1) f[i][j]^=(1<<j-1);
		}
	scanf("%d",&n);
	while (n--)
	{
		int l,r,ans=0;
		scanf("%d%d",&l,&r);
		for (int i=LG;i>=0;i--)
			if (l+(1<<i)-1<=r)
			{
				ans^=f[l][i]; l+=(1<<i);
				if ((cnt[r]-cnt[l-1])&1) ans^=(1<<i);
			}
		if (ans) printf("A");
			else printf("B");
	}
	return 0;
}

【CF1511G】Chips on a Board

原文:https://www.cnblogs.com/stoorz/p/14722916.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!