LuoguP5652 基础博弈练习题 博弈
归纳+找规律.
如果终点 $r$ 是奇数,那么 $r-m-1$ ~ $r-1$ 这段区间都是先手必败.
然后我们发现 $r-m-1$ 及之前都是偶数的话还是先手比败,直到遇到一个奇数,就又变成了先手必胜.
那么,对于一个奇数位置,其前面第一个先手必胜位置就是 $r-m-1$ 前第一个奇数位置.
对于偶数,我们发现是先手必败,而其前面第一个先手必胜点就是其前面第一个奇数点.
上述关系构成了一个树形结构,即偶数的话让前面第一个奇数连它,奇数的话让 $i-m-1$ 之前第一个奇数连它.
如果 $[l,r]$ 满足先手必胜,则要求 $l$ 在树上是 $r$ 的祖先,这个用 DFS 序判断一下就行了.
code:
#include <bits/stdc++.h>
#define N 1000009
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,m,q,type,deco[5],edges,tim;
int a[N],fa[N],hd[N],to[N],nex[N],st[N],ed[N];
void add(int u,int v) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs(int x) {
st[x]=++tim;
for(int i=hd[x];i;i=nex[i])
dfs(to[i]);
ed[x]=tim;
}
int RAN() {
return deco[0]=(deco[0]*deco[1]+deco[2])%deco[3];
}
void get(int &x,int &y) {
if(type==0) scanf("%d%d",&x,&y);
else {
x=RAN()%n+1,y=RAN()%n+1;
if(x>y) swap(x,y);
}
}
int main() {
// setIO("input");
scanf("%d%d%d%d",&n,&m,&q,&type);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
if(a[i]&1) {
if(i-m-1>0) {
if(a[i-m-1]&1) fa[i]=i-m-1;
else fa[i]=fa[i-m-1];
}
}
else {
if(a[i-1]&1) fa[i]=i-1;
else fa[i]=fa[i-1];
}
}
if(type==1) {
for(int i=0;i<4;++i) scanf("%d",&deco[i]);
}
for(int i=1;i<=n;++i) add(fa[i],i);
dfs(0);
int x,y,z;
ll ans=0;
ll mod=1ll<<32;
for(int i=1;i<=q;++i) {
get(x,y);
if(x==y) {
if(a[x]%2==0)
(ans+=(ll)i*i%mod)%=mod;
continue;
}
if(st[y]>=st[x]&&st[y]<=ed[x]) {
continue;
}
(ans+=(ll)i*i%mod)%=mod;
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号