[洛谷P5652]基础博弈练习题

题目

思路

cjr Orz

(f_i)表示第一个到(i)的人是否必胜,对于询问([l,r]),可以发现(f_r)只与(a_r)的奇偶性有关,奇数为1偶数为0

如果(f_i=1),那么(i)向前(m)位都有(f_j=0),对于点(i-m-1),如果有人到这里无路可走,他就必须向后走,一定会落到这(m)个位置之一中,即必输,所以(f_{i-m-1})的胜负也只与(a_{i-m-1})的奇偶性有关

如果(f_i=0),考虑(f_{i-1}),如果(a_{i-1})为偶数,假设(B_{i-1}=2)去试,如果A走进来,那么B可以不走出去,那么只能A走出去,但是后面能到达的点一定都是0(否则为什么(f_i)会为0),所以(f_{i-1}=0),奇数亦然;综上,(f_{i-1})的胜负与(a_{i-1})奇偶性相关

(i)作为右边界时,用上面两项可以推出此时它前面有哪些为1,将它和最近的1连边,没有就向0节点连边,每个点都会向前面一个点连边,显然会构成一个树形结构,一个点只有父亲节点都是必胜节点

判断([l,r])是否必胜,等价于判断(l)是不是(r)的父亲,用dfs序即可,注意特判(l==r)

Code

#include<bits/stdc++.h>
#define N 2000005
#define re register
using namespace std;
typedef long long ll;
int n,m,q,a[N],pre[N],type;
int size[N],dfn[N],c;
const ll mod = 4294967296;

template<class T>
void read(T &x)
{
	char c;int sign=1;
	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
struct Edge
{
	int next,to;
}edge[N];int head[N],cnt=1;
void add_edge(int from,int to)
{
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	head[from]=cnt;
}
ll A,B,C,P;
inline int rnd() { return A=(A*B+C)%P; }
void dfs(int rt)
{
	dfn[rt]=++c;
	size[rt]=1;
	for(int i=head[rt];i;i=edge[i].next)
	{
		int v=edge[i].to;
		dfs(v);
		size[rt]+=size[v];
	}
}
void init()
{
	for(re int i=1;i<=n;++i)
	{
		pre[i]=pre[i-1];
		if(a[i]) pre[i]=i;
	}
	for(re int i=1;i<=n;++i)
	{
		if(!a[i]) { add_edge(pre[i],i); continue; }
		int x=i-m-1;
		if(x>0) add_edge(pre[x],i);
		else add_edge(0,i);
	}
	dfs(0);
}
inline bool query(int x,int y)
{
	if(!a[y]) y=pre[y];
	return dfn[x]<=dfn[y]&&dfn[y]<=dfn[x]+size[x]-1;
}
int main()
{
	read(n);read(m);read(q);read(type);
	for(re int i=1;i<=n;++i) read(a[i]),a[i]%=2;
	init();
	ll ans=0;
	if(type)
	{	
		read(A);read(B);read(C);read(P);
		for(re ll i=1;i<=q;++i)
		{
			int l=rnd()%n+1,r=rnd()%n+1;
			if(l>r) swap(l,r);
			if(!m) ans=(ans+i*i*a[l]%mod)%mod;
			else if(!query(l,r)) ans=(ans+i*i%mod)%mod;
		}
	}
	else
	{
		for(re ll i=1;i<=q;++i)
		{
			int l,r;
			read(l);read(r);
			if(!m) ans=(ans+i*i*a[l]%mod)%mod;
			else if(!query(l,r)) ans=(ans+i*i%mod)%mod;
		}
	}
	cout<<(ans%mod+mod)%mod<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/Chtholly/p/11852998.html