【JZOJ3339】wyl8899和法法塔的游戏【暴力】

题目大意:

题目链接:https://jzoj.net/senior/#main/show/3339
一个序列 a a a,每次给定 l , r , R l,r,R l,r,R,在 [ l , r ] [l,r] [l,r]中选择一个点 x x x,先手第一次必须选择在第 R R R堆石子内取。求 [ x , R ] [x,R] [x,R] N I M NIM NIM博弈先手是否有必胜策略,若有择输出第一手先手取的石子个数。
询问之间互相关联。


思路:

对于每一组询问我们枚举区间 [ l , r ] [l,r] [l,r]中的 i i i,然后如果先手必胜,则说明先手在 a [ R ] a[R] a[R]中选择若干石子使得 a [ i ]   x o r   a [ i + 1 ]   x o r . . . x o r   a [ R ] = 0 a[i]\ xor\ a[i+1]\ xor...xor\ a[R]=0 a[i] xor a[i+1] xor...xor a[R]=0
x = a [ i ]   x o r   a [ i + 1 ]   x o r . . . x o r   a [ R − 1 ] x=a[i]\ xor\ a[i+1]\ xor...xor\ a[R-1] x=a[i] xor a[i+1] xor...xor a[R1]。那么则要找到合适的 a n s ans ans使得 x   x o r   ( a [ R ] − a n s ) = 0 x\ xor\ (a[R]-ans)=0 x xor (a[R]ans)=0
我们知道,有且仅有形如 p   x o r   p p\ xor\ p p xor p的情况下才可以等于0。所以我们所求即为 x = a [ R ] − a n s x=a[R]-ans x=a[R]ans
由于询问直接互相关联,我们不可以用前缀异或和。只需从 R R R倒序循环到 l l l,每次询问时暴力求异或和。注意只有下标 ≤ r \leq r r时才可以更新答案。
时间复杂度 O ( n m ) O(nm) O(nm)显然不可以过卡一卡就过去了。
正解是分块+可持久化 T r i e Trie Trie


代码:

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include 
#include 
#include 
#define reg register
using namespace std;

const int N=100010,Inf=2e9;
int n,T,ans,l,r,R,x,a[N];

int read()
{
	int d=0;
	char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) 
		d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

void write(int x)
{
	if (x>9) write(x/10);
	putchar(x%10+48);
}

int main()
{
	n=read();
	for (reg int i=1;i<=n;i++)
		a[i]=read();
	T=read();
	while (T--)
	{
		R=read(); l=read(); r=read();
		ans=Inf; x=0;
		if (!a[R]) puts("-1");
		else if (R==r) write(a[r]),putchar(10),a[r]=0;
		else 
		{
			for (reg int i=R-1;i>=l;i--)
			{
				x^=a[i];
				if (i<=r&&x<ans) ans=x;
			}
			if (a[R]-ans>0) write(a[R]-ans),putchar(10),a[R]=ans;
				else puts("-1");
		}
	}
	return 0;
}

你可能感兴趣的:(模拟)