zoukankan      html  css  js  c++  java
  • CF1149E Election Promises

    一、题目

    点此看题

    二、解法

    显然本题一定有终止态,感受一下就好了我不想证明。

    本题大概是把 ( t nim) 游戏放在 ( t DAG) 上然后改了点游戏规则,我们还是主要从 (xor) 的角度思考。

    首先把每个点按找 (mex) 分组,定义 (a_u) 为点 (u) 的组别:

    (a_u=mex{a_v | (u,v)in E})

    然后找稳态,也就是必胜方能维持必败方得到的状态。考虑对于组别 (p) 求出所有属于该组点的异或和 (xor(p)),那么稳态就是 (forall p,xor(p)=0),我们猜测初始状态是稳态就先手必败,否则先手必胜。

    我们只需要证明这两点,非稳态可以通过一步操作转到稳态,一步操作稳态只能转到非稳态:

    • 第一点,我们找到满足 (xor(p) ot=0) 的最大的 (p),找到其中 (h_u)(xor(p)) 最高位相同的一个点 (u),显然 (h_u) 是应该减少的,首先我们把 (h_u) 的最高位变成 (0),然后剩下的位就可以任取了,所以可以让 (xor(p)) 变成 (0);然后因为 (mex) 的性质,我们可以通过直连边改变任意编号 (<p) 的组别,所以可以让所有组的 (xor(p)=0)
    • 第二点,任取一个点 (u),那么改变它的 (h_u) 会使 (xor(a_u)>0),因为 (mex) 的性质也无法通过直连边把它改回来,所以稳态只能转到非稳态。

    那么跑拓扑排序就可以判断是否先手必胜了,如果先手必胜按上面的方法操作到稳态即可。

    三、总结

    解决非常规博弈问题的重要方法:找稳态,有稳态就有必胜策略。

    分组是解决一个点对另一个点有影响的重要方法,博弈问题一定要多应用 (mex)(xor) 这两个玄学玩意。

    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int M = 200005;
    int read()
    {
        int x=0,f=1;char c;
        while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
        while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
        return x*f;
    }
    int n,m,k,a[M],b[M],s[M],h[M],d[M],id[M];
    vector<int> g[M];queue<int> q;
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		h[i]=read();
    	for(int i=1;i<=m;i++)
    	{
    		int u=read(),v=read();
    		g[u].push_back(v);d[v]++;
    	}
    	for(int i=1;i<=n;i++)
    		if(!d[i]) q.push(i);
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		id[++k]=u;//tuopu order
    		for(auto v:g[u])
    		{
    			d[v]--;
    			if(!d[v]) q.push(v);
    		}
    	}
    	for(int i=k;i>=1;i--)
    	{
    		int u=id[i];
    		for(auto v:g[u]) b[a[v]]=1;
    		for(int x=0;;x++) if(!b[x])
    		{
    			a[u]=x;
    			break;
    		}
    		for(auto v:g[u]) b[a[v]]=0;
    	}
    	for(int i=1;i<=n;i++)
    		s[a[i]]^=h[i];
    	int pd=0,rt=0;
    	for(int i=0;i<=n;i++)
    		if(s[i]) pd=1;
    	if(!pd)
    	{
    		puts("LOSE");
    		return 0;
    	}
    	puts("WIN");
    	for(int i=1;i<=n;i++) if(s[a[i]])
    		if(a[i]>=a[rt] && (s[a[i]]^h[i])<h[i])
    			rt=i;
    	for(auto v:g[rt])
    		if(s[a[v]]) h[v]=s[a[v]]^h[v],s[a[v]]=0;
    	h[rt]=s[a[rt]]^h[rt];
    	for(int i=1;i<=n;i++)
    		printf("%d ",h[i]);
    }
    
  • 相关阅读:
    IDEA中getgetServletContext()报错
    会话跟踪小结
    Sklearn-CrossValidation交叉验证
    js定时器 数码时钟
    centos7 新建用户并获取root权限
    linux cetos7 yum 安装redis
    mybatis 中 使用 List<Map<String,Object>> Map<String,Object>接收结果
    Mybatis resultMap 中 collection association 的用法
    各大型邮箱smtp服务器及端口收集: SMTP
    Mybatis 动态sql 示例 复杂类型对象 作为参数进行取值
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15190324.html
Copyright © 2011-2022 走看看