ABC162D RGB Triplets
RGB Triplets
题目大意:有一个长度为 \(n\) 的字符串 \(s\),只包含字符 R
G
B
,找出满足以下两个条件的三元组 \((i, j, k)\)\((1 \le i < j < k \le n)\):
- \(s_i \ne s_j\) ,\(s_i \ne s_k\),\(s_j \ne s_k\)。
- \(j - i \ne k - j\)
首先 \(O(n^3)\) 的大暴力是过不了的>︿<
所以要优化到 \(O(n^2)\)
因为我们要得到三个字母不同的子序列,所以可以直接考虑用乘法原理。之后再进行遍历把满足 \(j - i = k - j\) 的情况去掉即可,后期遍历方式如下图:
\(j \ \xrightarrow{i} \ j + i+ 1 \xrightarrow{i} \ j + 2 \times i + 2\)
我们从第 \(j\) 个字符开始,向后扩展 \(i\) 个字符,得到第 \(j + i + 1\) 个字符。在此基础上,再向后扩展 \(i\) 个字符,得到第 \(j + 2 \times i + 2\) 个字符。则这三个字符不满足条件二,如果这三个字符满足 RGB
各有一个,那么就要在 \(ans\) 中减去 \(1\),因为虽然这三个字符不满足条件二,但因乘法原理算进了 \(ans\) 中。其中 \(i\) 由于三个相邻的不同字符也不满足条件二,所以 \(0 \le i \le \left\lfloor\dfrac{n - 3}{2}\right\rfloor\),而 \(j\) 满足 \(j \ge 1 \And j + i \times 2 + 2 \le n\)。
就直接看代码了:
#include <bits/stdc++.h>
using namespace std;
inline long long read(){ //快读
long long s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9'){
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
long long n, r, g, b;
unsigned long long ans; //usnigned 用不用好像都无所谓……
char s[4040]; //千万不能用string,不然会炸掉
int main(){
n = read();
for (int i = 1; i <= n; i++){
s[i] = getchar();
if (s[i] == 'R') r++; //对r, g, b计算一个初始值,方便使用乘法原理
if (s[i] == 'G') g++;
if (s[i] == 'B') b++;
}
ans = r * g * b; //乘法原理预处理ans,但多出来很多的不符合条件的答案
int _n = (n - 3) >> 1; //计算(n-3)/2
for (int i = 0; i <= _n; i++){ //枚举两个字符之间的差
for (int j = 1; j + 2 * i + 2 <= n; j++){ //枚举j的大小
if (s[j] != s[j+i+1] && s[j] != s[j+i*2+2] && s[j+i+1] != s[j+i*2+2]){ //如果满足条件1,就将ans--
ans--;
}
}
}
cout << ans << endl;
return 0;
}