【CF】【博弈论】C. Permutation Game

C. Permutation Game

image

铺垫

必胜态

当前玩家具有掌握胜局的状态

必败态

当前玩家无法摆脱输局的必然状态


在两个人的博弈中,一个人的胜利是建立在另一个人的失败的事实上,因而一个人若处于必胜态,那么另一个必然处于必败态。

题意

若一个(a_j>a_i),且(|j-i|modspace a_i==0),当前玩家可以从i向j转移,从而将问题丢给下一个玩家。重复操作,直到一个玩家无法再继续转移下去。

在这题中必败态是必然存在的,因为最大值是无法再向其他位置转移的,即便是没有任何位置向最大值转移,第二大值也是必败态。同时任何能够向必败态转移的状态都是必胜态。

因而,我们可以在实际的处理的过程默认当前位置是必败态,如果能转到一个确切的必败态,再把当前位置的状态重新修改为必胜态。

同时用记忆化搜索来减少不必要的搜索量。

此外,作为博弈,每一个人都希望能够转移到一个对方为必败态的情况,这样自己就胜利了。

#include <bits/stdc++.h>
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define pi acos(-1.0)
#define PII pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define lowbit(x) (x&-x)
using namespace std;
const int N = 1E5+20;
int n,dp[N],A[N];
vector<int > vec[N];
int dfs(int x)
{
	if(dp[x]!=-1) return dp[x];
	int defa=0;
	for(int i=0;i<vec[x].size();i++)
	{
		if(!dfs(vec[x][i]))
	    {
	    	defa=1;
	    	break;
		}
	}

	return dp[x]=defa;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	   cin>>A[i];
	char c[N];
	for(int i=1;i<=n;i++)
	{
		for(int j=i+A[i];j<=n;j=j+A[i])
			if(A[j]>A[i])
			   vec[i].push_back(j);
		
		for(int j=i-A[i];j>=1;j=j-A[i])
	        if(A[j]>A[i])
	           vec[i].push_back(j);
	}
	memset(dp,-1,sizeof(dp));
	for(int i=1;i<=n;i++)
	    if(dp[i]==-1) dfs(i);
	for(int i=1;i<=n;i++)
		cout<<(dp[i]==1?'A':'B');//dp[i]=1代表必胜态 ,dp[i]代表必败态 
    return 0;
}

原文地址:https://www.cnblogs.com/BeautifulWater/p/15299598.html