题解 加与乘

传送门

发现 A 先手时 A 必败的条件是
序列的两端存在 0 或 序列中存在 \(\geqslant 2\) 个连续 0 或 存在长度为偶数的全 1 序列
前两个条件是因为这两个性质 B 可以一直保持
最后一个是因为 A 将其消完后会出现两个连续 0
B 先手时 A 必败条件是 B 可以用恰好一次操作弄出 A 先手时 A 必败的序列
大力分类讨论即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int a[N];

namespace force{
	int f[25][1<<22];
	int encode(int* a, int n) {
		int ans=0;
		for (int i=1; i<=n; ++i) ans|=a[i]<<i;
		return ans;
	}
	void decode(int* a, int n, int code) {
		for (int i=1; i<=n; ++i)
			if (code&(1<<i)) a[i]=1;
			else a[i]=0;
	}
	int dfs(int now, int n, int s) {
		if (~f[n][s]) return f[n][s];
		bool any_win=0, any_lose=0;
		int *t=&f[n][s], sta[22], tem[22];
		memset(sta, 0, sizeof(sta));
		memset(tem, 0, sizeof(tem));
		decode(sta, n, s);
		if (n==1) {return *t=(sta[1]==0);}
		for (int i=1; i<n; ++i) {
			for (int j=1; j<i; ++j) tem[j]=sta[j];
			for (int j=i+2; j<=n; ++j) tem[j-1]=sta[j];
			tem[i]=sta[i]^sta[i+1];
			if (dfs(now^1, n-1, encode(tem, n-1))) any_win=1;
			else any_lose=1;
			tem[i]=sta[i]&sta[i+1];
			if (dfs(now^1, n-1, encode(tem, n-1))) any_win=1;
			else any_lose=1;
		}
		if (!now) *t=any_win?1:0; // A first
		else *t=any_lose?0:1;
		// cout<<"dfs: "<<now<<' '<<n<<" ("; for (int i=1; i<n; ++i) cout<<sta[i]<<','; cout<<sta[n]<<") "<<*t<<endl;
		return *t;
	}
	void init() {memset(f, -1, sizeof(f));}
	void solve() {
		for (int i=1; i<=n; ++i) a[i]&=1;
		puts(dfs(m, n, encode(a, n))?"A":"B");
	}
}

namespace task{
	void solve() {
		for (int i=1; i<=n; ++i) a[i]&=1;
		if (!m) {
			if (!(a[1]&a[n])) {puts("A"); return ;}
			for (int i=2; i<=n; ++i) if (a[i-1]==0 && a[i]==0) {puts("A"); return ;}
			int cnt=0; a[n+1]=0;
			for (int i=1; i<=n+1; ++i) {
				if (a[i]&1) ++cnt;
				else {
					if (!(cnt&1)) {puts("A"); return ;}
					else cnt=0;
				}
			}
			puts("B");
		}
		else {
			if (!(a[1]|a[n])) {puts("A"); return ;}
			bool once=0;
			if (!(a[1]&a[n])) once=1;
			for (int i=2; i<=n; ++i) if (a[i-1]==0 && a[i]==0) {
				if (once) {puts("A"); return ;}
				else once=1;
			}
			int cnt=0; a[n+1]=0;
			for (int i=1; i<=n+1; ++i) {
				if (a[i]&1) ++cnt;
				else {
					if (!(cnt&1)) {
						if (once) {puts("A"); return ;}
						else once=1;
					}
					else cnt=0;
				}
			}
			puts(once?"B":"A");
		}
	}
}

signed main()
{
	freopen("game.in", "r", stdin);
	freopen("game.out", "w", stdout);

	int T=read();
	force::init();
	while (T--) {
		n=read(); m=read();
		for (int i=1; i<=n; ++i) a[i]=read();
		// if (n>30) puts("A");
		// else force::solve();
		if (n<=2) force::solve();
		else task::solve();
	}

	return 0;
}
posted @ 2022-03-18 17:27  Administrator-09  阅读(2)  评论(0编辑  收藏  举报