石头剪刀布

题目

对于一个包含字符 \(\{R,P,S\}\) 的字符串 \(s\),满足每相邻两个字符都不同且 \(s_1=s_n=R\)
你可以做两种操作:

  • 找出第一个 \(RS\)\(SR\) 将其替换为 \(R\)
  • 找出第一个 \(SP\)\(PS\) 将其替换为 \(S\)
    若无法进行任意一个操作则结束,否则继续执行,计操作序列为 \(b\)
    给你一个长为 \(n\) 的字符串 \(s\) 包含 \(\{R,P,S,?\}\),你可以将 \(?\) 替换为 \(\{R,P,S\}\) 中的一个使得其字符串满足上述条件,并对其进行操作得到 \(b\),问有多少方案,两个方案不同当且仅当 \(s\)\(s'\)\(b\)\(b'\) 至少有一个不同。\(n\leq 200\)

题解

首先 \(R\) 是无法删除的,那么我们希望用 \(R\) 来把问题分成若干段。注意到,我们每次删除 \(P\) 的时候,一定是删除最开头的 \(P\)(除 \(RPR\) 这唯一一个特例删不掉 \(P\))。但 \(S\) 就没有这么好的性质了。

所以设 \(f[i][j][k]\) 表示考虑前 \(i\) 个位置,第 \(i\) 个位置是 \(R\),且第 \(i\) 个位置前面有 \(j\)\(S\) 未被删除(这 \(j\)\(S\) 不被 \(P\) 包裹),后面有 \(k\)\(S\) 要删除时的答案。转移时,枚举下一个 \(R\) 的位置,那么中间的部分一定是 \(S\)\(P\) 交替出现。
肯定没法直接转移到因为中间的 \(S\) 可能会被 \(P\) 包裹而不能直接删掉,不满足 \(f\) 的状态定义(例如 \(RPSPR\)),所以可以考虑再记录另一个 \(dp\)\(g[i][l][j][k][0/1][0/1]\) ,其中 \(i,j,k\) 与上面类似,\(l\) 表示中间的部分里 \(P\) 还有几个,中间的部分的 开头\(/\)结尾 不是\(/\)\(S\)\(1\) 表示是 \(S\))。
\(f,g\) 定义的直观解释如:

还有一个问题就是考虑 \(RSPSPSR\) 删掉一个 \(P\) 后就会变成 \(RSSPSR\),导致它中间 \(S,P\) 不再交替,这个形式是没有状态来记录的。但是我们可以将他微调为 \(SRSPSR\),即把第一个 \(S\) 交换到 \(R\) 的前面,那这个就有状态就可以记录了,而且它仍然满足可以直接删掉。
为了方便我们写代码和转移,我们可以稍微改一下 \(g\) 的状态,我们让中间那段的左端必须是 \(P\),前面一旦出现 \(S\) 就扔到 \(R\) 左边,并将第一个 \(0/1\) 改为记录其左端 \(R\) 的左边还有没有 \(S\)

转移比较多,可以自己先推一下试试,但其实还是有点难度的。

转移

对于 \(f[j]*\)\(f[i]*,g[i]*\) 的转移:
枚举上一个 \(R\) 的位置 \(j\) 及其状态,枚举中间段的左右端点是 \(fl,fr\),可以算得中间段 \(P\) 的个数是 \(p=\frac{i-j-fl-fr}{2}\)

  • 特殊处理 \(RSR\) 的情况:
    • \(f[i][k][l-1]\gets f[j][k][l],l\geq 1\)(因为 \(l\geq 1\) 所以这个 \(S\) 要删。)
    • \(f[i][k+1][l]\gets f[j][k][l],l==0\)\(l==0\) 这个 \(S\) 不用删。)
  • 否则有转移:
    • \(g[i][p][k+fl][t][fl][fr]\gets f[j][k][l]\),对于 \(j\) 位置需要往后删掉 \(l\)\(S\),那么 \([j,i]\) 这一段中目前能直接删掉的 \(S\) 就是开头和结尾的两个(如果他们是 \(S\) 的话)所以如果 \(t\geq 1,fl=1\)\(t--,fl=0\)\(fr\) 同样(初始 \(t=l\))。

对于 \(g[x]*\)\(f[x]*\) 的转移:

  • 特判 \(RPR\) 的情况 \(f[x][j][k]\gets g[x][i][j][k][fl][fr]\)
  • 删除一个 \(S\)
    • \(g[x][i][j-1][k][fl][fr]\gets g[x][i][j][k][fl][fr],j>1\)
    • \(g[x][i][0][k][0][fr]\gets g[x][i][j][k][fl][fr],j==1\)(如果左边只剩一个 \(S\),删除后左边没有 \(S\)\(fl=0\)
    • \(g[x][i][0][k][0][0]\gets g[x][i][0][k][0][1]\)(左边没有能删的 \(S\) 了,那删除 \(fr\) 处的 \(S\)
    • \(g[x][i][0][k+1][0][0]\gets g[x][i][0][k][0][0]\)(目前已经没有 \(S\) 了,那么 \(k+1\),告诉后面还要多删一个 \(S\)
  • 删除一个 \(P\):一定删掉了最左边的 \(P\),那么他一定会新露出一个 \(S\),我们把他直接扔到 \(R\) 左边。注意当中间的 \(P\) 只剩一个的时候就已经不存在被 \(P\) 包裹的 \(S\) 了,所以要 \(i>1\)\(g[x][i-1][j+1][k][1][fr]\gets g[x][i][j][k][fl][fr],i>1\)
  • \(P\) 只剩一个的时候,更新答案 \(f[x][j+fr][k]\gets g[x][i][j][k][fl][fr],i==1\)

转移就这么多。

\(f\) 的状态数有三维,转移 \(O(n)\)\(g\) 的状态数有四维,转移 \(O(1)\),所以时间复杂度为 \(O(n^4)\)
\(g\) 数组可以滚动,空间复杂度为 \(O(n^3)\)。常数很小,可以通过。

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;inline ll read(){ll s=0,k=1;char c=getchar();while(c>'9'||c<'0'){if(c=='-') k=-1;c=getchar();}while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();}return s*k;
}const int N=1005,M=205,mod=998244353;
char s[N];
int n;
ll g[M][M][M][2][2],f[M][M][M];void Add(ll &x,ll y){x+=y;if(x>=mod) x-=mod;
}bool ok(char x,int y){if(x=='?') return 1;if(y==1&&x!='S') return 0;if(y==0&&x!='P') return 0;return 1;
}void clear(int n,int m,int K){for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)for(int k=0;k<=K;k++)for(int fll=0;fll<2;fll++)for(int flr=0;flr<2;flr++) g[i][j][k][fll][flr]=0;
}void solve(ll f[M][M],int n,int m,int K){for(int i=n;i>=1;i--)for(int j=m;j>=0;j--)for(int k=0;k<=K;k++)for(int fll=1;fll>=0;fll--)for(int flr=1;flr>=0;flr--)if(g[i][j][k][fll][flr]){ll &v=g[i][j][k][fll][flr];if(i==1&&!fll&&!flr){Add(f[j][k],v);continue;}if(j==1) Add(g[i][0][k][0][flr],v);else if(j>1) Add(g[i][j-1][k][fll][flr],v);else if(flr) Add(g[i][j][k][fll][0],v);else Add(g[i][j][k+1][fll][flr],v);if(i>1) Add(g[i-1][j+1][k][1][flr],v);else Add(f[j+flr][k],v);}
}int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);scanf("%s",s+1);n=strlen(s+1);f[1][0][0]=1;for(int i=2;i<=n;i++){if(s[i]!='?'&&s[i]!='R') continue;clear(i>>1,i>>1,n-i+1>>1);for(int flr=0;flr<2;flr++)for(int j=i-2;j>=1;j--){int fll=i-j-2+flr&1;if(!ok(s[j+1],fll)) break;for(int k=0;k<=j>>1;k++)for(int l=0;l<=n-j+1>>1;l++)if(f[j][k][l]){if(j==i-2&&flr){if(l) Add(f[i][k][l-1],f[j][k][l]);else Add(f[i][k+1][l],f[j][k][l]);continue;}	int t=l,p=i-j+1-fll-flr-1>>1;int fl0=fll,fl1=flr;if(t&&fl0) t--,fl0--;if(t&&fl1) t--,fl1--;Add(g[p][k+fl0][t][fl0][fl1],f[j][k][l]);}}solve(f[i],i>>1,i>>1,n-i+1>>1);}ll ans=0;for(int i=0;i<=n;i++) Add(ans,f[n][i][0]);printf("%lld",ans);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/874900.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新春“码”启 | 0 基础开发微信小游戏,Cocos 游戏引擎 + AI 辅助编程(第1天)

春节期间,老牛同学计划借助 AI 开启一场挑战自我和为小朋友开发微信小游戏的系列计划,0 基础开始了第1天的体验。目标是采用 Cocos 游戏引擎框架,借助 AI 辅助编程,最终完成微信小游戏研发。目前已对相关概念有了初步了解,后续将持续探索……好羡慕小朋友们,已经放了快两…

grammarly 使用问题

1 Word 使用时,有时下面的图标不出现,无法使用 2 3

那是我们的影子

那是我们的影子 题目描述 由 $3 \times n$ 个单元格构成的 $3$ 行 $n$ 列异形数独规则如下:每一个单元格都需要填入 $1$ 到 $9$ 之间的整数; 任意一个 $3 \times 3$ 的子矩阵中都不包含重复的数字;现在,牛可乐已经填入了一些数字,请你在此基础上帮助他计算,这个异形数独一…

NPS如何安装Windows版的客户端

Windows 首先下载Windows版的客户端: github下载地址:https://github.com/yisier/nps/releases 54 雨云ROS下载地址:https://cn-sy1.rains3.com/rainyun-assets/Pic/2023/11/windows_amd64_client.tar.gz 51我在需要运行NPS客户端的Windows设备的C盘根目录下建立一个名字叫【…

通过宝塔Docker安装NPS客户端

# 拉取 yisier1/npc 镜像 docker pull yisier1/npc安装拉取镜像成功后如下图所示:创建容器: 选择:命令创建 # 运行 npc 容器,按提示改好命令,如下图所示 docker run -d --name=npc --restart=always --net=host yisier1/npc -server=<ip:port> -vkey=<web界面中…

DeepSeekR1本地可视化运行!同时支持GPT4,Gemini,Cluade,Ollama所有开源模型

昨天使用Ollama在本地运行了DeepSeek R1这个可以深度思考的AI模型。通过这种方式可以快速体验模型,但是要长期高频使用的话,通过命令行这种方式终究是不太方便。所以今天来分享一个可视的软件ChatWise。 添加图片注释,不超过 140 字(可选)这是一个独立开发者开发的软件,界…

[ABC266Ex] Snuke Panic (2D) 题解

[ABC266Ex] Snuke Panic (2D) 题解 前言 前几天看到了这个,发现自己还真没仔细思考过。 做了两道题,把这个题当个总结。 思路 设 \(f_i\) 表示:在 \(T_i\) 走到第 \(i\) 个节点的最大收益。 有转移:\(f_i=\max \{f_j\} + A_i\)。 其中 \(j\) 需要满足:\(y_j\le y_i\) \(T_i…

DeepSeek R1果然有点意思! Windows本地使用ollama轻松跑起来。

这段时间国内外讨论DeepSeek的人都比较多,我印象比较深的是,Deepseek用较低的成本训练了一个不错的模型。另一个是说最近的R1可以匹敌chatgpt的o1。 对比chatgpt的模型很多,我也不知道是宣传而已,还是真的这么牛逼。所以准备本地运行一下看看。因为ollama上已经有这个模型了…

跟着狂神学java-第一天

Markdown学习 标题 (一个#+空格,一级标题) 二级标题 (两个#+空格,二级标题) 三级标题 (以此类推。。。) 字体helloworld (两个星号,加粗) hello world ( 一个星号,斜体) hello world (三个*,加粗的斜体) hello world (两个~,删除线) hello world…

36. 打印机

一、打印机应用程序一般都有打印功能,可以将重要内容打印成纸质资料。PySide6 支持打印操作,它可以识别系统中已经安装的打印机,驱动打印机进行工作,可以用与打印机有关的类直接打印,也可通过打印对话框进行打印,还可对打印的内容在打印前进行打印预览。与打印有关的类主…

MiniCPM-o 2.6 本地部署记录,Windows+RTX3060全部跑通!

上一篇中,大致聊了下国产小钢炮MiniCPM的特性,看起来很不错,可玩性很高。今天,主要来说一下,如何在本地运行这个项目。 添加图片注释,不超过 140 字(可选)配置过程花了一些时间,最终还是成功了,可以正常进行视频通话,语音通话,和聊天机器人。安装和测试过程中遇到了…

CTF-web-计算器

1.打开题目2.发现只能输入一个数字 3.查看源代码4.修改参数5.可以正确输入后得到flag