题解 CF1784E【Infinite Game】

\(\lim\limits_{x\to\infty}\frac{x+1}{2x}=\frac{1}{2}\)(洛必达法则)

在最后一步看了题解,终于意识到上式成立。

Problem

CF1784E Infinite Game

出题人:tourist

crxis 和 Robin 正在用双人博弈游戏消遣时间。他们有一个有限长度的字符串 \(s\),由 \(a,b\) 组成,用 \(s\) 生成了本次游戏的“策略” \(S=sss...\) 即无数个 \(s\) 首尾相接而成的无限字符串。

crxis 和 Robin 决定用这个“策略”进行游戏。他们手上各有一个计数器 \(crx=0,rob=0\),除此之外还有计数器 \(i=1,x=0,s=0\)。游戏以这样的方式进行:

  • 取出 \(S_i\),如果 \(S_i=a\),那么 \(crx\) 自增;否则 \(rob\) 自增。
  • 如果 \(crx=2\),那么 \(crx\) 归零,\(x\) 自增,\(s\) 自增。
  • 如果 \(rob=2\),那么 \(rob\) 归零,\(s\) 自增。
  • \(i\) 自增。(自增的意思是,例如 \(x\) 自增表示 \(x\gets x+1\)

随着这场无尽的游戏进行,crxis 想分析一下自己的赢面,他定义 \(r=\frac{x}{s}\),随着 \(s\) 趋向无穷,如果 \(r=\frac{1}{2}\) 那么他们平局;如果 \(r<\frac{1}{2}\) Robin 胜;否则 crxis 胜。

crxis 沉迷游戏,他想知道有多少种方案可以赢。他给你模式串 \(t\)\(a,b,?\) 组成,可以将 \(?\) 替换为 \(a\)\(b\),全部替换之后得到的 \(t\) 生成一个“策略”,那么可以判断这个“策略”的输赢。有多少种替换方案使得 crxis 赢,或平局,或败于 Robin 之手呢?

\(|t|\leq 200\)

Solution

观察到这个游戏的局面无非只有 \(0:0,1:0,0:1,1:1\) 四种。画出一个自动机刻画游戏的进程,这个自动机应接受一个字符串,根据字符串有一个小人在自动机的零点开始走,如果这个字符是 \(a\) 走到哪里哪里,是 \(b\) 走到哪里哪里。对于一些特殊的边,边权为 \(+1\) 表示 Alice 终于赢了,边权为 \(-1\) 表示 Bob 终于赢了,让小人抓住这个边权求和。

那么我们可以轻易的判断一个 \(s\) 是否是赢的,只要一直在自动机上跑,直到走进一个巨大的环,看一下这个环中小人拿到的边权和是 \(0\) 还是 \(>0\) 还是 \(<0\),分别对应 Tie,Alice,Bob。(千万不要认为进入环前面那一段是有用的,因为环的重复次数太大,进入环前面那一段的影响很小;或者可以用类似于 \(\lim\limits_{x\to\infty}\frac{x+1}{2x}=\frac{1}{2}\) 的东西理解)

那么对于不确定的 \(s\) 我们直接 DP:\(f(\{u_0,u_1,u_2,u_3\})\) 分别对应从 \(0:0,1:0,0:1,1:1\) 出发,现在在哪里。DP 完之后就能把环接上,模拟出最终状态。你可能还需要记录这四种分别对应的权值和。复杂度非常巨大:\(O(4^4\times n^5)\)。那么这样卡常能过,更好的做法是由于我们只关心环,枚举环由什么东西组成,加到同一个地方,复杂度骤降为 \(O(2^4\times 4^4\times n^2)\) 随便过。貌似建了五个点的能过,但是计算环外的一定过不去。

Code

点击查看代码

#include <cstdio>
#include <vector>
#include <cstring>
#include <cassert>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
const int P=998244353;
void red(int&x){x%=P;}
int mod(int x){return (x%P+P)%P;}
int n,col[4][4][4][4];
int f[210][4][4][4][4][1010],ans[3];
int table[4][4]={
	{1,0,3,0},
	{0,1,0,1},
	{2,3,0,0},
	{0,0,-1,-1}
};
char s[210];
void dp(int S){
	memset(f,0,sizeof f);
	f[0][0][1][2][3][500]=1;
	for(int i=1;i<=n;i++){
		for(int u0=0;u0<4;u0++)
		for(int u1=0;u1<4;u1++)
		for(int u2=0;u2<4;u2++)
		for(int u3=0;u3<4;u3++)
		for(int w=0;w<=1000;w++){
			if(!f[i-1][u0][u1][u2][u3][w]) continue;
			int *to,*q;
			auto run=[&](){
				int tmpw=w;
				if(S&1) tmpw+=q[u0];
				if(S&2) tmpw+=q[u1];
				if(S&4) tmpw+=q[u2];
				if(S&8) tmpw+=q[u3];
				red(f[i][to[u0]][to[u1]][to[u2]][to[u3]][tmpw]+=f[i-1][u0][u1][u2][u3][w]);
			};
			if(s[i]=='a'||s[i]=='?') to=table[0],q=table[1],run();
			if(s[i]=='b'||s[i]=='?') to=table[2],q=table[3],run();
		}
	}
	for(int u0=0;u0<4;u0++)
	for(int u1=0;u1<4;u1++)
	for(int u2=0;u2<4;u2++)
	for(int u3=0;u3<4;u3++){
		if(S==col[u0][u1][u2][u3]){
			for(int w=0;w<=1000;w++){
				int t=f[n][u0][u1][u2][u3][w];
				if(w==500) red(ans[1]+=t);
				else if(w<500) red(ans[2]+=t);
				else red(ans[0]+=t);
			}
		}
	}
}
void init(){
	for(int u0=0;u0<4;u0++)
	for(int u1=0;u1<4;u1++)
	for(int u2=0;u2<4;u2++)
	for(int u3=0;u3<4;u3++){
		auto trans=[&](int u){
			switch(u){
				case 0: return u0;
				case 1: return u1;
				case 2: return u2;
				case 3: return u3;
			}
			assert(0); return -1;
		};
		int now=0;
		int vis[4]; memset(vis,0,sizeof vis);
		for(int t=1;t<=15;t++) vis[now]++,now=trans(now);
		int T=0;
		for(int i=0;i<4;i++) if(vis[i]>1) T+=1<<i;
		col[u0][u1][u2][u3]=T;
	}
}
int main(){
//	#ifdef LOCAL
//	 	freopen("input.in","r",stdin);
//	#endif
	debug("sizeof f=%zu\n",sizeof f>>20);
	scanf("%s",s+1),n=strlen(s+1),init();
	for(int S=0;S<1<<4;S++) dp(S);
	for(int i=0;i<3;i++) printf("%d\n",mod(ans[i]));
	return 0;
}

posted @ 2023-07-16 09:21  caijianhong  阅读(21)  评论(0编辑  收藏  举报