Codeforces Round 984 (Div. 3) C题题解
C. Anya and 1100
题解
首先我们先了解什么是模拟:
模拟就是用计算机来模拟题目中要求的操作,将题目要求转换为代码
解模拟题需要多打草稿理清逻辑思路,以这题为例:
题目要求在每次查询s[i-1]=v
后判断字符串s中是否存在字串“1100”;
表面看是考察字符串的子串匹配,但如果我们使用strstr()
或者find()
来查找子串,在O(nq)的时间复杂度下,很容易TLE;
而且模式串“1100”较短也没有前后缀相等,更不可能用KMP或BM解决
于是我们考虑模拟q的查询操作:
由图
每次对pos位置的字符进行修改:
- 如果修改前后的字符保持不变,即
s[pos]==v
,则不造成影响 - 如果
s[pos]!=v
,则更改字符造成影响的区间为[pos-3,pos+3] - 所以我们只需要对[pos-3,pos+3]的区间进行子串的查找,大大减少查找次数
那么对该区间的查找结束了,如何判断整个字符串s是否存在子串“1100”呢?
我们可以在q次操作之前用朴素匹配算法查找s中出现子串"1100"的总次数,即:
bool is1100(ll i, string &p)
{
if (i < 0)
return false;
if (i >= n - 3)
return false;
// 用于处理pos+3>n和pos-3<0的边界情况
if (p[i] == '1' && p[i + 1] == '1' && p[i + 2] == '0' && p[i + 3] == '0')
{
return true;
}
return false;
}
int main()
{
cin >> t;
while (t--)
{
ll cnt = 0;//子串出现的次数
cin >> s;
cin >> q;
n = s.length();
for (ll i = 0; i < n; i++)
{
if (is1100(i, s))
{
cnt++;
}
}
}
}
之后每次字符修改,cnt的值都可能变化:
- 如果
s[pos]!=v
,cnt不变; - 如果
s[pos]==v
,则计算修改前后[pos-3,pos+3]区间子串“1100”的出现次数,cnt加上两者之差
每次操作结束后,当cnt<=0
时输出NO,否则输出YES;
while (q--)
{
int l;
char r;
cin >> l >> r;
l--;
if (r != s[l])
{
bool origin = is1100(l - 3, s) || is1100(l - 2, s) || is1100(l - 1, s) || is1100(l, s);
s[l] = r;
bool current = is1100(l - 3, s) || is1100(l - 2, s) || is1100(l - 1, s) || is1100(l, s);
cnt += current - origin;
}
string res = cnt ? "YES\n" : "NO\n";
cout << res;
}
完整代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n = 0; // 字符串的长度
int t, q;
string s;
bool is1100(ll i, string &p)
{
if (i < 0)
return false;
if (i >= n - 3)
return false;
// 用于处理pos+3>n和pos-3<0的边界情况
if (p[i] == '1' && p[i + 1] == '1' && p[i + 2] == '0' && p[i + 3] == '0')
{
return true;
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> t;
while (t--)
{
ll cnt = 0;
cin >> s;
cin >> q;
n = s.length();
for (ll i = 0; i < n; i++)
{
if (is1100(i, s))
{
cnt++;
}
}
while (q--)
{
int l;
char r;
cin >> l >> r;
l--;
if (r != s[l])
{
bool origin = is1100(l - 3, s) || is1100(l - 2, s) || is1100(l - 1, s) || is1100(l, s);
s[l] = r;
bool current = is1100(l - 3, s) || is1100(l - 2, s) || is1100(l - 1, s) || is1100(l, s);
cnt += current - origin;
}
string res = cnt ? "YES\n" : "NO\n";
cout << res;
}
}
return 0;
}