[洛谷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;
}

猜你喜欢

转载自www.cnblogs.com/Chtholly/p/11852998.html