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; }