[ARC 188A] ABC Symmetry
solution by XiangXunYi
思路推导
step 1
首先题目中操作二同时删掉 A,B,C 的条件相当于同时将三者数量减一,操作一删掉两个相同字符等同于将某一字符的数量减二,那么我们可以发现只使用操作一不会改变奇偶,操作二则是同时反转奇偶,所以一个字符串是个好字符串的必要条件是其中三个字母数量的奇偶性相同,同时容易构造出一组解使其变为空字符串,故也是必要条件。
构造解:执行操作一直到不能执行为止,最后视情况执行操作二。
step2
由于题目的抽象数据范围较小且对于问号的抉择相互影响较大,联想到 dp。首先会想到把 \(K\) 放入 dp 状态中来 check 是否合法,但我们发现每次新增一个字符时算贡献是需要枚举之前前缀三个字符的奇偶性,但上一个状态又并不完全由所枚举的单个状态转移过来,dp 的转移就很扑朔迷离(至少我是这样)。所以要改变 dp 的定义,但又要计算好子段个数,所以状态必须能计算 \(K\) 值。
step 3
设一段区间 A 的数量对 \(2\) 取模为 \(a\),B 的数量对 \(2\) 取模为 \(b\),C 的数量对 \(2\) 取模为 \(c\)。
因为好字段必须要三个字符数量奇偶性相同,抽象的理解为 \(0/1\) 状态,即区间和为 \(0\),前缀和呀!只要两点的前缀和值相等,这个区间就是一个好子段。我们设计一个 dp 状态 \(dp_{i,j,k,l,0/1/2/3}\) 表示存在 \(i\) 个位置前缀区间满足情况 \(0\)[1],\(j\) 个位置前缀区间满足情况 \(1\)[2],\(k\) 个位置前缀区间满足情况 \(2\)[3],\(l\) 个位置前缀区间满足情况 \(3\)[4]且上一个位置前缀区间满足情况 \(0/1/2/3\) 的方案数。
在这种 dp 状态的设计下,我们可以发现,四种情况不重不漏的涵盖了所有区间,当一个区间满足右端点和左端点减一是同一种情况就是一个好子段,最后好子段的个数就是 \(\frac{i \times (i + 1) + j \times (j - 1) + k \times (k - 1) + l \times (l - 1)}{2}\) 答案即为所有该值大于 \(K\) 的 \(dp_{i,j,k,l,0/1/2/3}\) 累加起来。
step 4
定义有了,该题的转移并不难想,只要根据上一个位置的状态加上当前位置的字符即可转移(给个建议:用刷表)。
solution
定义 \(dp_{i,j,k,l,lst \in \{0/1/2/3\}}\) 表示有 \(i\) 个前缀满足情况 \(0\),\(j\) 个前缀满足情况 \(1\),\(k\) 个前缀满足情况 \(2\),\(l\) 个前缀满足情况 \(3\),上一个前缀的情况为 \(lst\)。
对于当前字符为 A 时,情况 \(0\) 与情况 \(3\) 互换,情况 \(1\) 与情况 \(2\) 互换。
对于当前字符为 B 时,情况 \(0\) 与情况 \(1\) 互换,情况 \(2\) 与情况 \(3\) 互换。
对于当前字符为 C 时,情况 \(0\) 与情况 \(2\) 互换,情况 \(1\) 与情况 \(3\) 互换。
int pos = i + j + k + l;
int tmp[4] = { i, j, k, l };
int x = lst ^ 3, y = lst ^ 1, z = lst ^ 2;
if ((s[pos] == '?' || s[pos] == 'A') && tmp[x] + 1 <= n) {
tmp[x]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][x] , dp[i][j][k][l][lst]);
tmp[x]--;
}
if ((s[pos] == '?' || s[pos] == 'B') && tmp[y] + 1 <= n) {
tmp[y]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][y] ,dp[i][j][k][l][lst]);
tmp[y]--;
}
if ((s[pos] == '?' || s[pos] == 'C') && tmp[z] + 1 <= n) {
tmp[z]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][z] , dp[i][j][k][l][lst]);
tmp[z]--;
}
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
const int mod = 998244353;
int n, least, dp[N][N][N][N][4];
char s[55];
inline void trans(int& x, int y) { x = (x + y) % mod; }
int main() {
scanf("%d%d%s", &n, &least, s);
dp[0][0][0][0][0] = 1;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k)
for (int l = 0; l < n; ++l)
if (i + j + k + l < n)
for (int lst = 0; lst < 4; ++lst) {
int pos = i + j + k + l;
int tmp[4] = { i, j, k, l };
int x = lst ^ 3, y = lst ^ 1, z = lst ^ 2;
if ((s[pos] == '?' || s[pos] == 'A') && tmp[x] + 1 <= n) {
tmp[x]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][x] , dp[i][j][k][l][lst]);
tmp[x]--;
}
if ((s[pos] == '?' || s[pos] == 'B') && tmp[y] + 1 <= n) {
tmp[y]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][y] ,dp[i][j][k][l][lst]);
tmp[y]--;
}
if ((s[pos] == '?' || s[pos] == 'C') && tmp[z] + 1 <= n) {
tmp[z]++;
trans(dp[tmp[0]][tmp[1]][tmp[2]][tmp[3]][z] , dp[i][j][k][l][lst]);
tmp[z]--;
}
}
int ans = 0;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= n; ++j)
for (int k = 0; k <= n; ++k)
for (int l = 0; l <= n; ++l)
for (int lst = 0; lst < 4; ++lst)
if (i + j + k + l == n && i * (i + 1) + j * (j - 1) + k * (k - 1) + l * (l - 1) >> 1 >= least)
trans(ans, dp[i][j][k][l][lst]);
printf("%d\n", ans);
return 0;
}
[ARC 188A] ABC Symmetry的更多相关文章
- Atcoder Rating System
来翻译一下官方文档,但是建议看英文原文,本文可能会出现一些错误,只是为了方便自己查阅用的. 对于你的每一场rated比赛,会有一个Performance值\(X_i\),你的rating是\(X_i- ...
- Solution -「ARC 110E」Shorten ABC
\(\mathcal{Description}\) Link. 给定长度为 \(n\),包含 A, B, C 三种字符的字符串 \(S\),定义一次操作为将其中相邻两个不相同的字符替换为字符集 ...
- iOS阶段学习第21天笔记(ARC内存管理-Copy-代理)
iOS学习(OC语言)知识点整理 一.OC 中的ARC内存管理 1)ARC中释放对象的内存原则:看这个对象有没有强引用指向它 2)strong:强引用,默认情况下的引用都是强引用 3) weak:弱引 ...
- 【iOS开发-33】学习手动内存管理临时抛弃ARC以及retain/assign知识——iOSproject师面试必考内容
我们为什么须要内存管理?当使用内存达到40M和45M时候会发出警告,假设不处理,占用内存达到120M时直接强制关闭程序. 所以出现闪退除了是程序出现逻辑错误,还有可能是内存使用过大. (1)创建一个对 ...
- 1.ARC下是否有内存溢出等问题 2.@property参数 3.#import和@class的区别
1.ARC下是否有内存溢出等问题? 答案:必须要担心啊,ARC也不是万能的.答案:必须要担心啊,ARC也不是万能的.这里主要是涉及到集合类的数据类型 比如数组,我们定义了一个可变数组muarr1, ...
- [题解] Atcoder Regular Contest ARC 147 A B C D E 题解
点我看题 A - Max Mod Min 非常诈骗.一开始以为要观察什么神奇的性质,后来发现直接模拟就行了.可以证明总操作次数是\(O(nlog a_i)\)的.具体就是,每次操作都会有一个数a被b取 ...
- Convert BSpline Curve to Arc Spline in OpenCASCADE
Convert BSpline Curve to Arc Spline in OpenCASCADE eryar@163.com Abstract. The paper based on OpenCA ...
- 黑马程序员——ARC机制总结和用ARC建立模型
ARC 全称:Automatic Reference Counting 使用ARC 只需要在建立一个新的项目的时候把 下面的√打上 Xcode5以后都会默认建议开发者使用ARC机制 新的项目中如果有部 ...
- 【IOS】将一组包含中文的数据按照#ABC...Z✿分组
上一篇文章[IOS]模仿windowsphone列表索引控件YFMetroListBox里面 我们一步步的实现了WindowsPhone风格的索引. 但是有没有发现,如果你要实现按照字母排序,你还得自 ...
- JSONKit在项目中使用设置(ARC与方法更新)
在项目中经常会遇到解析json的情况,如果有同学想要解析JSON,那么JSONKit可以是一个不错的选择. git中JSONKit 的地址为:https://github.com/johnezang/ ...
随机推荐
- 利用腾讯元器,将公众号变身为强大的.NET AI智能体
前言 经常有粉丝朋友在公众号后台私信提问,因为个人平时比较少看公众号后台的私信所以没法及时回复.最近发现腾讯推出了一个可以创建和使用各种智能体的平台(帮助小白也能快速使用AI):腾讯元器,正好自己每天 ...
- 7、listener监听
启动远程图形界面登录的工具 [root@db11g ~]# vncserver 监听 监听的启动 [oracle@db11g ~]$ lsnrctl start 判断监听是否启动 [oracle@db ...
- re中文匹配
Pattern = re.compile(u'[\u4e00-\u9fa5]+') if Pattern.search(searchstring): # do something else: # do ...
- canvas(三)绘制矩形
1.绘制矩形轨迹 相关语法:ctx.rect(x,y,width,height),根据传入的参数(起始坐标和宽高)用来绘制一个矩形轨迹 注意:ctx.rect()和ctx.lineTo()绘制的都是轨 ...
- AI产品落地的多角度探索与实践
AI产品落地的多角度探索与实践是一个复杂而多维的过程,它涉及技术创新.行业应用.人机协作等多个方面.在构建多智能体平台Agent Foundry的基础上,我们可以将其应用于制造业.教育.政府.跨境电商 ...
- 非root用户使用AntDeploy部署docker
AntDeploy这个东西非常好用,可以直接将.NET CORE的程序直接发布到docker,刚好我有这个需求,但是程序默认给的账户示例是root账户的,需要对于需要分散开发的同学来说,这个东西风险有 ...
- rpc-java 生成代码路径设置
<plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf- ...
- Qt编写安防视频监控系统68-兼容Qt4到Qt6
一.前言 为了从Qt4.7兼容到Qt6.2及后续版本,着实花了不少精力,前提也是对自定义控件大全和各种跨平台的轮子组件全部做成了兼容Qt4到Qt6,这样只剩下UI这块需要兼容就好办多了,各个击破战略, ...
- JVM实战—3.JVM垃圾回收的算法和全流程
大纲 1.JVM内存中的对象何时会被垃圾回收 2.JVM中的垃圾回收算法及各算法的优劣 3.新生代和老年代的垃圾回收算法 4.避免本应进入S区的对象直接升入老年代 5.Stop the World问题 ...
- MFC-error C2589: “(”:“::”右边的非法标记
MFC-error C2589: "(":"::"右边的非法标记 错误信息 出错语句 问题原因 解决办法 错误信息 ① 错误 C2589 "(&quo ...