jzoj3339. wyl8899和法法塔的游戏

博客围绕石子游戏展开,描述了游戏规则,玩家需根据给定区间求最大弱菜值。给出了多组输入输出示例及数据约束。题解介绍了两种做法,一是分块建可持久化trie,二是建权值线段树,还提及了各自的时间复杂度,最后给出代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

Description
法法塔和wyl8899都喜欢玩游戏。但是每次玩游戏法法塔都被wyl8899虐。

为了安慰可怜的法法塔,wyl8899决定大发慈悲,修改了一下游戏规则。

是这样的,这儿有一堆石子排成一列,每次wyl8899让hza选择一个区间进行游戏。游戏嘛,就是采用最普通的规则:两人轮流操作,每次选择一堆石子,取掉不为0的石子数,没法操作者失败。法法塔要做的是这样的:

我们现在定义一个区间的弱菜值:表示如果法法塔先取石子,而且法法塔第一步取的石子规定是最右边的那堆的话,为了必胜,第一步需要取的石子数。如果没法获胜的话,那么弱菜值就是-1。

法法塔要选择一个区间[l,r],使得r为wyl8899给定的某个数,l属于[a,b],a,b也是wyl8899给定的,要求这个区间的弱菜值是满足前面的条件中最大。请给出这个最大的弱菜值。

如果最大弱菜值不为-1,法法塔就会马上取走该区间最右端的石子堆最大弱菜值数量的石子。

Input
第一行一个正整数n,描述了石子的堆数,接下来一行n个数,描述每堆石子的数目。

接下来一行m,表示将进行要进行m次游戏,每次游戏由三个值刻画,r,a,b。r表示被选定的右端点,[a,b]表示选择的区间的左端点的范围

Output
对于每个询问输出最大的弱菜值。

Sample Input
输入1:

12

662 477 125 483 17 560 232 59 176 928 807 659

5

5 2 5

4 4 4

2 1 2

6 4 6

6 2 3

输入2:

7

230 883 456 1020 966 899 610

2

7 1 2

2 1 2

输入3:

11

392 808 14 71 393 79 11 74 713 232 142

5

8 3 8

9 5 9

3 1 1

8 2 8

7 4 6

Sample Output
输出1:

17

483

477

560

-1

输出2:

352

883

输出3:

74

713

-1

-1

-1

Data Constraint
n<=100000,m<=10000,每堆的石子数<=1000。

题解

口胡警告
O3警告

题解的做法是把n分块,每个块建可持久化trie
每次修改就对整块打标记,对散块暴力
查找就尽量往小的找(因为这样剩下的才能尽量小)
时间复杂度:O(m*√n*logS)


下面是自己在考场上想到的sb做法
建1024棵权值线段树,每棵线段树对应一种异或后缀的出现位置
查找就暴力枚举判断对应区间内是否存在某个后缀
修改就相当于第R位改变的位置(设其对应的二进制为s)在1~R的异或后缀取反,等于把第i棵树和第i^s棵树的1~R区间交换
时间复杂度:O(m*1024*logn)

因为题解的复杂度写错了所以其实这样做更慢

code

因为是自己乱写的所以不删注释了

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define low(x) (x&(-(x)))
using namespace std;

int a[100001];
int tr[10000001][3];
int Tr[100001];
char s1[1400001];
int Q,n,i,j,k,l,Find,ans,R,A,B,s,len,I;
bool bz;
char *Ch=s1;

int getint()
{
	register int x=0;
	
	while (*Ch<'0' || *Ch>'9') *++Ch;
	while (*Ch>='0' && *Ch<='9') x=x*10+(*Ch-'0'),*++Ch;
	
	return x;
}

void swap(int &x,int &y)
{
	int z=x;
	x=y;
	y=z;
}

void New(int t,int x)
{
	if (!tr[t][x])
	tr[t][x]=++len;
}

void CHANGE(register int t,int s)
{
	while (t<=n)
	{
		Tr[t]^=s;
		t+=low(t);
	}
}
int FIND(register int t)
{
	register int S=0;
	
	while (t)
	{
		S^=Tr[t];
		t-=low(t);
	}
	
	return S;
}

void change(register int t,register int l,register int r,int x)
{
	register int mid=(l+r)/2;
	
	++tr[t][2];
	if (l==r) return;
	
	if (x<=mid)
	{
		New(t,0);
		change(tr[t][0],l,mid,x);
	}
	else
	{
		New(t,1);
		change(tr[t][1],mid+1,r,x);
	}
}

void exchange(register int fa1,register int fa2,register int t1,register int t2,register int l,register int r,int x,int y)
{
	register int mid=(l+r)/2;
	
	if (x<=l && r<=y)
	{
		swap(tr[fa1][tr[fa1][1]==t1],tr[fa2][tr[fa2][1]==t2]);
		return;
	}
	
	if (x<=mid && (tr[tr[t1][0]][2] || tr[tr[t2][0]][2]))
	{
		New(t1,0);
		New(t2,0);
		
		exchange(t1,t2,tr[t1][0],tr[t2][0],l,mid,x,y);
	}
	if (mid<y  && (tr[tr[t1][1]][2] || tr[tr[t2][1]][2]))
	{
		New(t1,1);
		New(t2,1);
		
		exchange(t1,t2,tr[t1][1],tr[t2][1],mid+1,r,x,y);
	}
	
//	cout<<tr[t1][2]<<" "<<tr[tr[t1][0]][2]+tr[tr[t1][1]][2]<<endl;
	
	tr[t1][2]=tr[tr[t1][0]][2]+tr[tr[t1][1]][2];
	tr[t2][2]=tr[tr[t2][0]][2]+tr[tr[t2][1]][2];
}

void find(register int t,register int l,register int r,int x,int y)
{
	register int mid=(l+r)/2;
	
	if (x<=l && r<=y)
	{
		Find+=tr[t][2];
		return;
	}
	
	if (x<=mid && tr[tr[t][0]][2])
	find(tr[t][0],l,mid,x,y);
	if (Find) return;
	
	if (mid<y  && tr[tr[t][1]][2])
	find(tr[t][1],mid+1,r,x,y);
}

int main()
{
//	freopen("A7_9_3.in","r",stdin);
//	freopen("A7_9_3.out","w",stdout);
	
	fread(s1,1,1400001,stdin);
	
	n=getint();
	len=1024;
	
	fo(i,1,n)
	{
		a[i]=getint();
		CHANGE(n-i+1,a[i]);
	}
	
	k=0;
	fd(i,n,1)
	{
		k^=a[i];
		change(k+1,1,n,i);
	}
	
	Q=getint();
	for (;Q;--Q)
	{
		R=getint(),A=getint(),B=getint();
		s=FIND(n-R+1);
		
//		cout<<"  "<<s<<endl;
		
//		if (Q==6- 3)
//		{
//			fo(i,0,1023)
//			{
//				Find=0;
//				find(i+1,1,n,2,2);
//				
////				cout<<Find<<endl;
//				if (Find)
//				cout<<i<<" "<<a[R]<<endl;
//			}
//		}
		
		fo(I,0,a[R]-1)
		{
			Find=0;
			find((I^s)+1,1,n,A,B);
			
			if (Find)
			break;
		}
		
//		Find=0;
//		find(s+1,1,n,A,B);
//		cout<<s<<" "<<Find<<" "<<A<<" "<<B<<endl;
//		return 0;
		
		if (I<a[R])
		{
			printf("%d\n",a[R]-I);
			s=a[R]^I;
			l=low(s);
			
//			cout<<s<<" "<<l<<endl;
			
			fo(i,0,1023)
			if (i&l)
			{
//				if (Q==6-2 && (i^s)==4)
//				{
//					cout<<tr[i+1][2]<<" "<<tr[(i^s)+1][2]<<endl;
//				}
				
				if (R<n)
				exchange(0,0,i+1,(i^s)+1,1,n,1,R);
				else
				{
					swap(tr[i+1][0],tr[(i^s)+1][0]);
					swap(tr[i+1][1],tr[(i^s)+1][1]);
					swap(tr[i+1][2],tr[(i^s)+1][2]);
				}
				
//				if (Q==6-2 && (i^s)==4)
//				cout<<tr[i+1][2]<<" "<<tr[(i^s)+1][2]<<endl;
				
//				if (Q==6-2 && (i^s)==4)
//				{
//					if (Q==6- 2)
//					{
//						fo(i,0,1023)
//						{
//							Find=0;
//							find(i+1,1,n,2,2);
//							
//			//				cout<<Find<<endl;
//							if (Find)
//							cout<<i<<" "<<a[R]<<endl;
//						}
//					}
//					return 0;
//				}
			}
			
			a[R]=I;
			CHANGE(n-R+1,s);
		}
		else
		printf("-1\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值