本文涉及知识点
P9183 [USACO23OPEN] FEB B
题目描述
贝西和埃尔希正在密谋最终推翻他们的主人------农夫约翰!他们通过 N N N 条短信进行计划。他们的对话可以用一个长度为 N N N 的字符串 S S S 来表示。
其中 S i S_i Si 是字母 B或 E,这意味着第 i i i 条消息分别由贝西或埃尔希发送的。
然而,农夫约翰听说了这个消息,并试图拦截他们的谈话。因此,字符串 S S S 的一些字母是 F,这意味着农夫约翰混淆了信息,发件人未知(贝西、埃尔希都有可能)。
注:约翰没有发送信息!他只是在干扰奶牛间的通话!
未混淆对话的兴奋程度是一只奶牛重复发送信息的次数 。也就是说,子串 BB或 EE在 S S S 中出现的次数。你想找到原始信息的兴奋程度,但你不知道约翰的信息中哪一条实际上是贝西或埃尔希的。在所有可能的情况下,从小到大输出所有可能的兴奋程度。
输入格式
第一行:一个整数 N N N(通话长度)。
第二行:一个字符串 S S S(通话内容)。
输出格式
第一行:输出一个整数 K K K,为不同 兴奋程度的可能数量。
随后 K K K 行:每行一个整数,为每种兴奋程度。注意按照从小到大的顺序输出。
输入输出样例 #1
输入 #1
4
BEEF
输出 #1
2
1
2
输入输出样例 #2
输入 #2
9
FEBFEBFEB
输出 #2
2
2
3
输入输出样例 #3
输入 #3
10
BFFFFFEBFE
输出 #3
3
2
4
6
说明/提示
1 ≤ N ≤ 2 × 10 5 1 \le N \le 2 \times 10^5 1≤N≤2×105。
- 测试点 4~8: N ≤ 10 N \le 10 N≤10
- 测试点 9~20:无额外限制。
P9183 [USACO23OPEN] FEB B
令m个F混淆前是s。如果s[0]=s[m - 1],则s的幸福度可能为 f 1 = m − 1 , m − 3 ⋯ f1={m-1,m-3 \cdots } f1=m−1,m−3⋯,最小值为0或1;如果 s [ 0 ] ≠ s [ m − 1 ] , 则 s 的幸福度可以为 f 2 = m − 2 , m − 4 ⋯ s[0]\neq s[m - 1], 则s的幸福度可以为f2 = { m - 2, m - 4 \cdots } s[0]=s[m−1],则s的幸福度可以为f2=m−2,m−4⋯,最小值为0或1。
两者是等差数量,公差-2。最小值大于等于0。s前面的字符为ch1,后面的字符为ch2。
c h 1 ≠ c h 2 ch1 \neq ch2 ch1=ch2,如果s[0]=s[m - 1],则s[0] 和ch1,s[m - 1] 和ch2必定一个相等,一个不等。即f1+1,最大值m, 最小值1或2。
如果 s [ 0 ] ≠ s [ m − 1 ] s[0]\neq s[m - 1] s[0]=s[m−1],则s[0] 和ch1,s[m - 1] 和ch2都相等,或都不等。即f2+0,f2+2。即最大值m,最小值0或1。
** 结论一**: c h 1 ≠ c h 2 ch1 \neq ch2 ch1=ch2,幸福度的可能值为 0 或 1 s i m m ,公差为 2 0或1 sim m,公差为2 0或1simm,公差为2。m为1,无需特殊处理。
如果ch1等于ch2:如果s[0]=s[m - 1],则s[0] 和ch1,s[m - 1] 和ch2都相等,或都不等。f1+0和f1+2。最大值m+1,最小值0或1。
如果 s [ 0 ] ≠ s [ m − 1 ] s[0]\neq s[m - 1] s[0]=s[m−1],则s[0] 和ch1,s[m - 1] 和ch2必定一个相等,一个不等。即j2+1。最大值m-1,最小值1或2。
** 结论二**:最大值m+1,最小值0或1,公差2.
** 结论三**:如果ch1,ch2都不存在,即整个字符串就是s。最大值m-1,最小值0,公差1。
** 性质一**:如果t的幸福度是x1,将t的A、B互换幸福度不变。
结论四 : 如果ch1和ch2有一个不存在,即s是整个字符串的前缀或后缀。结论三的结果+0,或+1。即 0 s i m m ,公差 1 0 sim m,公差1 0simm,公差1。
一个公差为K的等差数量,最小值为i1,最大值为a1。一个公差为K的等差数列,最小值为i2,最大值为a2。
两者相加可能值构成的等差数列,公差为K,最小值i1+i2,最大值a1+a2。
一个公差为2的等差数量,最小值为i1,最大值为a1。一个公差为1的等差数列,最小值为i3,最大值为a3。
如果i3等于a3(常数),则相加可能得结果仍然是公差为2的等差数量,最小值i1+i3,最大值a1+i3。
如果i3不等于a3,则结果的公差为1,最小值i1+i3,最大值a1+a3。
i 1 + i 3 , i 1 + ( i 3 + 1 ) , ( i 1 + 2 ) + i 3 , ( i 1 + 2 ) + ( i 3 + 1 ) ⋯ + a 1 + i 3 , a 1 + ( i 3 + 1 ) , a 1 + ( i 3 + 2 ) ⋯ {i1+i3,i1+(i3+1),(i1+2)+i3,(i1+2)+(i3+1)\cdots }+ {a1+i3,a1+(i3+1),a1+(i3+2)\cdots } i1+i3,i1+(i3+1),(i1+2)+i3,(i1+2)+(i3+1)⋯+a1+i3,a1+(i3+1),a1+(i3+2)⋯
先处理公差2的,再处理公差1(前缀、后缀), 最后处理常数(初始幸福度) 这样要么公差相等,要么公差为2,1。
代码
核心代码
cpp
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include<array>
#include <bitset>
using namespace std;
template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
in >> pr.first >> pr.second;
return in;
}
template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t);
return in;
}
template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
return in;
}
template<class T = int>
vector<T> Read() {
int n;
cin >> n;
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
template<class T = int>
vector<T> ReadNotNum() {
vector<T> ret;
T tmp;
while (cin >> tmp) {
ret.emplace_back(tmp);
if ('\n' == cin.get()) { break; }
}
return ret;
}
template<class T = int>
vector<T> Read(int n) {
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
template<int N = 1'000'000>
class COutBuff
{
public:
COutBuff() {
m_p = puffer;
}
template<class T>
void write(T x) {
int num[28], sp = 0;
if (x < 0)
*m_p++ = '-', x = -x;
if (!x)
*m_p++ = 48;
while (x)
num[++sp] = x % 10, x /= 10;
while (sp)
*m_p++ = num[sp--] + 48;
AuotToFile();
}
void writestr(const char* sz) {
strcpy(m_p, sz);
m_p += strlen(sz);
AuotToFile();
}
inline void write(char ch)
{
*m_p++ = ch;
AuotToFile();
}
inline void ToFile() {
fwrite(puffer, 1, m_p - puffer, stdout);
m_p = puffer;
}
~COutBuff() {
ToFile();
}
private:
inline void AuotToFile() {
if (m_p - puffer > N - 100) {
ToFile();
}
}
char puffer[N], * m_p;
};
template<int N = 1'000'000>
class CInBuff
{
public:
inline CInBuff() {}
inline CInBuff<N>& operator>>(char& ch) {
FileToBuf();
while (('\r' == *S) || ('\n' == *S) || (' ' == *S)) { S++; }//忽略空格和回车
ch = *S++;
return *this;
}
inline CInBuff<N>& operator>>(int& val) {
FileToBuf();
int x(0), f(0);
while (!isdigit(*S))
f |= (*S++ == '-');
while (isdigit(*S))
x = (x << 1) + (x << 3) + (*S++ ^ 48);
val = f ? -x : x; S++;//忽略空格换行
return *this;
}
inline CInBuff& operator>>(long long& val) {
FileToBuf();
long long x(0); int f(0);
while (!isdigit(*S))
f |= (*S++ == '-');
while (isdigit(*S))
x = (x << 1) + (x << 3) + (*S++ ^ 48);
val = f ? -x : x; S++;//忽略空格换行
return *this;
}
template<class T1, class T2>
inline CInBuff& operator>>(pair<T1, T2>& val) {
*this >> val.first >> val.second;
return *this;
}
template<class T1, class T2, class T3>
inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {
*this >> get<0>(val) >> get<1>(val) >> get<2>(val);
return *this;
}
template<class T1, class T2, class T3, class T4>
inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {
*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);
return *this;
}
template<class T = int>
inline CInBuff& operator>>(vector<T>& val) {
int n;
*this >> n;
val.resize(n);
for (int i = 0; i < n; i++) {
*this >> val[i];
}
return *this;
}
template<class T = int>
vector<T> Read(int n) {
vector<T> ret(n);
for (int i = 0; i < n; i++) {
*this >> ret[i];
}
return ret;
}
template<class T = int>
vector<T> Read() {
vector<T> ret;
*this >> ret;
return ret;
}
private:
inline void FileToBuf() {
const int canRead = m_iWritePos - (S - buffer);
if (canRead >= 100) { return; }
if (m_bFinish) { return; }
for (int i = 0; i < canRead; i++)
{
buffer[i] = S[i];//memcpy出错
}
m_iWritePos = canRead;
buffer[m_iWritePos] = 0;
S = buffer;
int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);
if (readCnt <= 0) { m_bFinish = true; return; }
m_iWritePos += readCnt;
buffer[m_iWritePos] = 0;
S = buffer;
}
int m_iWritePos = 0; bool m_bFinish = false;
char buffer[N + 10], * S = buffer;
};
class CCreatePrime {
public:
CCreatePrime(int iMax) :m_isPrime(iMax + 1, true)
{
m_isPrime[0] = m_isPrime[1] = false;
for (int i = 2; i <= iMax; i++)
{
if (m_isPrime[i])
{
m_vPrime.emplace_back(i);
}
for (const auto& n : m_vPrime)
{
if ((long long)n * i > iMax) { break; }
m_isPrime[n * i] = false;
if (0 == i % n) { break; }
}
}
}
vector<int> m_vPrime;
vector<bool> m_isPrime;
};
template<class T = int>
class CDiscretize //离散化
{
public:
CDiscretize(vector<T> nums)
{
sort(nums.begin(), nums.end());
nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
m_nums = nums;
for (int i = 0; i < nums.size(); i++)
{
m_mValueToIndex[nums[i]] = i;
}
}
int operator[](const T value)const
{
auto it = m_mValueToIndex.find(value);
if (m_mValueToIndex.end() == it)
{
return -1;
}
return it->second;
}
int size()const
{
return m_mValueToIndex.size();
}
vector<T> m_nums;
protected:
unordered_map<T, int> m_mValueToIndex;
};
template<long long MOD = 1000000007, class T1 = int, class T2 = long long>
class C1097Int
{
public:
C1097Int(T1 iData = 0) :m_iData(iData% MOD)
{
}
C1097Int(T2 llData) :m_iData(llData% MOD) {
}
C1097Int operator+(const C1097Int& o)const
{
return C1097Int(((T2)m_iData + o.m_iData) % MOD);
}
C1097Int& operator+=(const C1097Int& o)
{
m_iData = ((T2)m_iData + o.m_iData) % MOD;
return *this;
}
C1097Int& operator-=(const C1097Int& o)
{
m_iData = ((T2)MOD + m_iData - o.m_iData) % MOD;
return *this;
}
C1097Int operator-(const C1097Int& o)const
{
return C1097Int(((T2)MOD + m_iData - o.m_iData) % MOD);
}
C1097Int operator*(const C1097Int& o)const
{
return((T2)m_iData * o.m_iData) % MOD;
}
C1097Int& operator*=(const C1097Int& o)
{
m_iData = ((T2)m_iData * o.m_iData) % MOD;
return *this;
}
C1097Int operator/(const C1097Int& o)const
{
return *this * o.PowNegative1();
}
C1097Int& operator/=(const C1097Int& o)
{
*this /= o.PowNegative1();
return *this;
}
bool operator==(const C1097Int& o)const
{
return m_iData == o.m_iData;
}
bool operator<(const C1097Int& o)const
{
return m_iData < o.m_iData;
}
C1097Int pow(T2 n)const
{
C1097Int iRet = (T1)1, iCur = *this;
while (n)
{
if (n & 1)
{
iRet *= iCur;
}
iCur *= iCur;
n >>= 1;
}
return iRet;
}
C1097Int PowNegative1()const
{
return pow(MOD - 2);
}
T1 ToInt()const
{
return ((T2)m_iData + MOD) % MOD;
}
private:
T1 m_iData = 0;;
};
class Solution {
public:
vector<int> Ans(const string& s) {
const int N = s.size();
int mi2 = 0, ma2 = 0;
int mi1 = 0, ma1 = 0;
int x0 = 0;
for (int i = 1; i < N; i++) {
if (s[i] != s[i - 1]) { continue; }
x0 += ('F' != s[i]);
}
vector<pair<int, int>> beginLen;
for (int i = 0; i < N; i++) {
if ('F' != s[i]) { continue; }
if (beginLen.size() && (beginLen.back().first + beginLen.back().second == i)) {
beginLen.back().second++;
}
else {
beginLen.emplace_back(i, 1);
}
}
for (const auto& [left, len] : beginLen) {
const int r = left + len - 1;
const bool b1 = (0 != left);
const bool b2 = (N != r + 1);
if (b1 && b2) {
if (s[left - 1] == s[r + 1]) {
ma2 += (len + 1);
mi2 += (len + 1) % 2;
}
else {
ma2 += len;
mi2 += len % 2;
}
}
else if ((!b1) && (!b2)) {
ma1 += (len - 1);
}
else {
ma1 += len;
}
}
mi1 += x0; ma1 += x0;
vector<int> ans;
if (mi1 == ma1) {
for (int i = mi2; i <= ma2; i += 2) {
ans.emplace_back(i + mi1);
}
}
else {
for (int i = mi1 + mi2; i <= ma1 + ma2; i++) {
ans.emplace_back(i);
}
}
return ans;
}
};
int main() {
#ifdef _DEBUG
freopen("a.in", "r", stdin);
#endif // DEBUG
//ios::sync_with_stdio(0); cin.tie(nullptr);
//CInBuff<> in; COutBuff<10'000'000> ob;
int N;
cin >> N ;
string s;
cin >> s;
#ifdef _DEBUG
//printf("N=%d", N);
//Out(que, ",que=");
//Out(a, ",a=");
//Out(B, "B=");
//Out(que, "que=");
//Out(B, "B=");
#endif // DEBUG
auto res = Solution().Ans(s);
cout << res.size() << "\n";
for (const auto& i : res) {
cout << i << "\n";
}
return 0;
}
单元测试
cpp
string s;
TEST_METHOD(TestMethod01)
{
s = "BBEE";
auto res = Solution().Ans(s);
AssertEx({ 2 }, res);
}
TEST_METHOD(TestMethod02)
{
s = "BBF";
auto res = Solution().Ans(s);
AssertEx({ 1,2 }, res);
}
TEST_METHOD(TestMethod03)
{
s = "BEEF";
auto res = Solution().Ans(s);
AssertEx({ 1,2 }, res);
}
TEST_METHOD(TestMethod04)
{
s = "FEBFEBFEB";
auto res = Solution().Ans(s);
AssertEx({ 2,3 }, res);
}
TEST_METHOD(TestMethod05)
{
s = "BFFFFFEBFE";
auto res = Solution().Ans(s);
AssertEx({ 2,4,6 }, res);
}
TEST_METHOD(TestMethod06)
{
s = "FFF";
auto res = Solution().Ans(s);
AssertEx({0, 1,2 }, res);
}
扩展阅读
| 我想对大家说的话 |
|---|
| 工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
| 学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
| 有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
| 闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
| 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
| 如果程序是一条龙,那算法就是他的是睛 |
| 失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。