[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/ ...
随机推荐
- 什么是静态方法?@staticmethod装饰器怎么用?
填坑(@staticmethod装饰器----静态方法声明) > 在学习的时候看到很多人都在用@Staticmethod这个装饰器来修饰类方法,这就让我好奇了这个独特的装饰器到底是个啥?咋就受到 ...
- 基本数据结构-双端队列(Deque)
6.基本数据结构-双端队列(Deque) 一.双端队列(Deque) - 概念:deque(也称为双端队列)是与队列类似的项的有序集合.它有两个端部,首部和尾部,并且项在集合中保持不变. - 特性:d ...
- Linux下使用谷歌输入法
Linux的中文输入法一直太烂,scim终于出来对googlePinyin的支持了. 安装步骤: 1.安装scim: sudo apt-get install scim 2.从git上checkout ...
- Java深度历险(一)——Java字节代码的操纵
[编者按]Java作为业界应用最为广泛的语言之一,深得众多软件厂商和开发者的推崇,更是被包括Oracle在内的众多JCP成员积极地推动发展.但是对于Java语言的深度理解和运用,毕竟是很少会有人涉及的 ...
- weex跨页面通信
需求: A页面有表单和表格,点击表格中的按钮到B页面,B页面操作完毕,再次回到A页面,表单元素保持不变,表格内容刷新. 通过管道通信去做,用两个管道嵌套,A页面跳转到B页面的时候,直接用管道发过去,B ...
- vue中获取v-for循环出来的元素的相对于父级的最左边的距离
- 《JavaScript 模式》读书笔记(7)— 设计模式2
这一篇我们主要来学习装饰者模式.策略模式以及外观模式.其中装饰者模式稍微复杂一点,大家认真阅读,要自己动手去实现一下哦. 四.装饰者模式 在装饰者模式中,可以在运行时动态添加附加功能到对象中.当处理静 ...
- Powershell 源码批判
代码里充斥着过程式编程的搞法:比如这里 Utils.PathIsUnc,分散的到处都是 internal static IEnumerable<string> GetDefaultAvai ...
- 【Python】【爬虫】【爬狼】003_获取搜索结果的页数
# 获取搜索内容的页数 需要的包 import urllib.request # 获取网页源码 import re # 正则表达式,进行文字匹配 from bs4 import BeautifulSo ...
- /etc/rancher/k3s/registries.yaml
mirrors: "192.168.50.3": endpoint: - "https://192.168.50.3"configs: "192.16 ...