1. 程式人生 > 實用技巧 >CF919F A Game With Numbers

CF919F A Game With Numbers

能轉移到必敗態的狀態就是必勝態,只能轉移到必勝態的狀態就是必敗態。

首先我們可以把狀態壓縮,發現狀態最多隻有 495 種。

然後如果一方是全 0 ,那麼這個狀態對應的答案就可以很容易得出

然後反著思考,從上面說的這些已知狀態逆向搜尋

DFS(m1,m2,k) 表示 A 是 m1 狀態,B 是 m2 狀態,k=0/1 表示當前是 A/B 操作的回合

每一個 m1,m2,k 只需要被搜尋一次,所以可以用一個 vis 陣列記憶一下有沒有搜過

注意,我們是從結果推到初始狀態,所以這裡的轉移也是倒過來轉移

如果當前狀態是必敗態,那麼轉移到下一個狀態(其實是上一個)就一定是必勝態,因為 能轉移到必敗態的狀態就是必勝態

如果當前狀態是必勝態,那麼就把能轉移到的狀態的計數器自增,如果某個狀態的計數器到達了能轉移到他的狀態的個數,那麼那個狀態就成為了必敗態,因為 只能轉移到必勝態的狀態就是必敗態

如果當前狀態不是必勝也不是必敗,那就別轉移給其他狀態,因為不確定

到最後還是不確定的起始狀態那就是 Deal

然後把所有狀態都預處理好,查詢直接輸出即可

至於記搜的複雜度... \(\mathcal O(\text{能過})\)

\(\texttt{Code}\)

// This code wrote by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
#define mem(x,y) memset(x,y,sizeof x)
#define ln puts("")
using namespace std;
template <class t> inline void read(t &s){s=0;
reg int f=1;reg char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))s=(s<<3)+(s<<1)+(c^48),c=getchar();s*=f;return;}
template<class t,class ...A> inline void read(t &x,A &...a){read(x);read(a...);}
template <class t> inline void write(t x){if(x<0)putchar('-'),x=-x;
int buf[21],top=0;while(x)buf[++top]=x%10,x/=10;if(!top)buf[++top]=0;
while(top)putchar(buf[top--]^'0');return;}
int idx[9][9][9][9],idxcnt;
int rev[500][5];
bool win[500][500][2],vis[500][500][2];
int cnt[500][500][2],Sum[500];
inline void dfs(int m[2],int k)
{
	for(int i=0;i<=4;++i)
		for(int j=1;j<=4;++j)
			if(rev[m[k^1]][i]&&rev[m[k]][j])
			{
				reg int c=(i-j+5)%5;
				if(!c)
					continue;
				reg int t[5];memcpy(t,rev[m[k^1]],sizeof t);
				--t[i],++t[c];
				reg int nxtm[2];nxtm[0]=m[0],nxtm[1]=m[1];
				nxtm[k^1]=idx[t[0]][t[1]][t[2]][t[3]];
				if(vis[nxtm[0]][nxtm[1]][k^1])
					continue;
				if(!win[m[0]][m[1]][k])
					win[nxtm[0]][nxtm[1]][k^1]=vis[nxtm[0]][nxtm[1]][k^1]=true,
					dfs(nxtm,k^1);
				else
				{
					if(++cnt[nxtm[0]][nxtm[1]][k^1]==Sum[nxtm[0]]*Sum[nxtm[1]])
						vis[nxtm[0]][nxtm[1]][k^1]=true,dfs(nxtm,k^1);
				}
			}
	return;
}
inline void work()
{
	reg int m[2],k,x;
	read(k);
	int t[5];mem(t,0);
	for(int i=1;i<=8;++i)
		read(x),++t[x];
	m[0]=idx[t[0]][t[1]][t[2]][t[3]];
	mem(t,0);
	for(int i=1;i<=8;++i)
		read(x),++t[x];
	m[1]=idx[t[0]][t[1]][t[2]][t[3]];
	puts(vis[m[0]][m[1]][k]?((win[m[0]][m[1]][k]^k)?"Alice":"Bob"):"Deal");
	return;
}
signed main(void)
{
	for(int i=0;i<=8;++i)
		for(int j=0;i+j<=8;++j)
			for(int k=0;i+j+k<=8;++k)
				for(int l=0;i+j+k+l<=8;++l)
					idx[i][j][k][l]=++idxcnt,
					rev[idxcnt][0]=i,rev[idxcnt][1]=j,rev[idxcnt][2]=k,
					rev[idxcnt][3]=l,rev[idxcnt][4]=8-i-j-k-l,
					Sum[idxcnt]=(!!j)+(!!k)+(!!l)+(!!rev[idxcnt][4]);
	for(int i=1;i<idxcnt;++i)
	{
		vis[idxcnt][i][0]=vis[i][idxcnt][0]=
		vis[idxcnt][i][1]=vis[i][idxcnt][1]=true;
		win[idxcnt][i][0]=win[i][idxcnt][1]=true;
		int m[2];
		m[0]=idxcnt,m[1]=i,dfs(m,0),dfs(m,1);
		m[0]=i,m[1]=idxcnt,dfs(m,0),dfs(m,1);
	}
	int t;read(t);
	while(t--)
		work();
	return 0;
}