• 【洛谷P5652】基础博弈练习题【dfs】【博弈论】


    题目:

    题目链接:https://www.luogu.org/problem/P5652
    YSGH和YGSH在打膈膜,YSGS在旁边围观。

    规则是这样的,先给定一个正整数mm和一个nn个数序列BB,一开始有一个棋子在BB的第一个位置,并将B1B_1减去11。此后双方轮流操作,每次操作,假设当前棋子在ii,可以把棋子移到一个位置jj,满足j[i,min(i+m,n)]jin[i,min(i+m,n)]Bj>0B_j>0,然后将BjB_j11,YSGH先手,谁先不能操作谁输。

    众所周知,YSGH和YGSH都是绝顶聪明的,所以两人都会使用最优策略。

    而隔膜使用的序列BB是一个序列AA的一个连续非空子序列,当然序列AA和每次隔膜使用的序列BB都是YSGS定的。

    现在他们进行了qq轮游戏,给出每轮游戏使用的区间,请你判断每轮谁会赢。


    思路:

    如果位置ii先手是必败的,那么[im,i1][i-m,i-1]先手都只要跳到ii,就使得当前选择的后手必败。也就是先手必胜。
    那么如果[i+1,i+m][i+1,i+m]均为先手必胜,那么当选择到ii时,如果ii为奇数,那么最终就是先手取完这堆石子,那么必败的石子堆时后手先取,所以先手必胜。反之,如果为偶数,先手必败。
    所以我们维护出每一个位置iinxt[i]nxt[i],表示满足aja_j为奇数且j<ij<ijj尽量大的jj
    所以如果ii必胜,那么nxt[im1]nxt[i-m-1]也必胜。所以如果我们从nxt[im1]nxt[i-m-1]ii连边,那么区间[l,r][l,r]如果满足llnxt[r]nxt[r]的祖先,那么就先手必败,否则先手必胜。
    判断是否为祖先节点可以用dfsdfs序来O(1)O(1)解决。


    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=1000010;
    const ll MOD=(1LL<<32);
    int n,m,Q,l,r,type,tot,a[N],head[N],nxt[N],dfn[N],size[N];
    ll ans;
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    int A,B,C,P;
    inline int rnd(){return A=(A*B+C)%P;}
    
    void add(int from,int to)
    {
    	e[++tot].to=to;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs(int x)
    {
    	dfn[x]=++tot; size[x]=1;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		dfs(v);
    		size[x]+=size[v];
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d%d%d",&n,&m,&Q,&type);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		if (a[i]&1) nxt[i]=i;
    			else nxt[i]=nxt[i-1];
    		if (i-m-1>0) add(nxt[i-m-1],i);
    			else add(0,i);
    	}
    	tot=0;
    	dfs(0);
    	if (type) scanf("%d%d%d%d",&A,&B,&C,&P);
    	for (int i=1;i<=Q;i++)
    	{
    		if (type)
    		{
    			l=rnd()%n+1,r=rnd()%n+1;
    			if (l>r) swap(l,r);
    		}
    		else scanf("%d%d",&l,&r);
    		if (!(dfn[l]<=dfn[nxt[r]] && dfn[l]+size[l]>=dfn[nxt[r]]+size[nxt[r]]))
    			ans=(ans+1LL*i*i)%MOD; 
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    Revit二次开发-IExternalCommand中Execute函数的三个参数
    WebApi接收传值
    IIS报错不进入网站关于webconfig问题
    Sugar和MiniUI的分页问题
    python可变参数类型 a,*args,**kwargs
    python3反转列表的三种方式
    自动化测试常用断言的使用方法(python)-(转载@zhuquan0814
    python深浅拷贝的理解和区分
    已存在提示
    SSH
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11997981.html
Copyright © 2020-2023  润新知