题解 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;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/solution-cf1784e.html