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

  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值