PROBLEM LINK:
Practice
Contest: Division 1
Contest: Division 2
Contest: Division 3
Contest: Division 4
Author: ro27
Tester: jay_1048576
Editorialist: iceknight1093
DIFFICULTY:
1371
PREREQUISITES:
None
PROBLEM:
A Schrödinger’s Smiley is a string that consists of a ':'
, followed by several ')'
(but at least one), followed by another ':'
.
For example, :):, :))):, :))))):
are Schrödinger’s Smileys.
Given a string S, find the number of its strings that are Schrödinger’s Smileys.
EXPLANATION:
This is, for the most part, an implementation task — checking each substring in \mathcal{O}(N^2) will be too slow, so a faster solution is necessary.
There are a couple of different observations that can be made here, leading to different implementations.
Method 1
One observation that can be made is that is two adjacent characters in the string are equal, we can remove one of them: it won’t affect the answer at all since smileys don’t care about how many ')'
there are.
So, we can create a reduced string R with the same answer as the original string, which has the property that no adjacent characters are equal.
To create R in \mathcal{O}(N), the following algorithm can be used:
- Initially, let R be empty.
- For each i from 1 to N:
- If R is not empty and S_i equals the last character of R, do nothing.
- Otherwise, append S_i to R.
Computing the answer on this reduced string in \mathcal{O}(N) is easy: notice that the only possible Schrödinger’s Smiley in it is :):
, so just check every substring of length 3.
Method 2
Another observation that can be made is that a Schrödinger’s Smiley can only occur between two consecutive occurrences of ':'
in S.
So, we can store the positions of all the occurrences of ':'
in S, then only check substrings that are between consecutive occurrences.
That is,
- Let \text{pos} be a list of positions of occurrences of
':'
in S. - Then, check the substrings [\text{pos}_1, \text{pos}_2], [\text{pos}_2, \text{pos}_3], [\text{pos}_3, \text{pos}_4], \ldots
This obviously takes \mathcal{O}(N) time since all the substrings we’re checking are disjoint.
TIME COMPLEXITY
\mathcal{O}(N) per testcase.
CODE:
Author's code (Method 1 - C++)
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
template<class T>
using oset = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
// order_of_key(a) -> gives index of the element(number of elements smaller than a)
// find_by_order(a) -> gives the element at index a
#define accelerate ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define int long long int
#define ld long double
#define mod1 998244353
#define endl "\n"
#define ff first
#define ss second
#define all(x) (x).begin(),(x).end()
#define ra(arr,n) vector<int> arr(n);for(int in = 0; in < n; in++) {cin >> arr[in];}
const int mod = 1e9 + 7;
const int inf = 1e18;
int MOD(int x) {int a1 = (x % mod); if (a1 < 0) {a1 += mod;} return a1;}
int power( int a, int b) {
int p = 1; while (b > 0) {if (b & 1)p = (p * a); a = (a * a) ; b >>= 1;}
return p;
}
void lessgoo()
{
int n;
cin >> n;
string s;
cin >> s;
string ans = "";
ans += s[0];
for (int i = 1; i < s.size(); i++) {
if (s[i] != ans.back()) {
ans += s[i];
}
}
int cnt = 0;
if (ans.size() < 3) {
cout << 0 << endl;
return;
}
// cout << ans << endl;
for (int i = 0; i <= ans.size() - 3; i++) {
if (ans[i] == ':' && ans[i + 2] == ':' and ans[i + 1] == ')')cnt++;
}
cout << cnt << endl;
}
signed main()
{
accelerate;
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int test = 1;
cin >> test;
for (int tcase = 1; tcase <= test; tcase++)
{
// cout << "Case #" << tcase << ": ";
lessgoo();
}
return 0;
}
Tester's code (Method 2 - C++)
/*...................................................................*
*............___..................___.....____...______......___....*
*.../|....../...\........./|...../...\...|.............|..../...\...*
*../.|...../.....\......./.|....|.....|..|.............|.../........*
*....|....|.......|...../..|....|.....|..|............/...|.........*
*....|....|.......|..../...|.....\___/...|___......../....|..___....*
*....|....|.......|.../....|...../...\.......\....../.....|./...\...*
*....|....|.......|../_____|__..|.....|.......|..../......|/.....\..*
*....|.....\...../.........|....|.....|.......|.../........\...../..*
*..__|__....\___/..........|.....\___/...\___/.../..........\___/...*
*...................................................................*
*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 1000000000000000000
#define MOD 1000000007
void solve(int tc)
{
int n;
cin >> n;
string s;
cin >> s;
int ans = 0;
for(int i=0;i<n;i++)
{
if(s[i]==':')
{
bool ok = true;
int j = i+1;
for(;j<n;j++)
{
if(s[j]==':')
break;
else if(s[j]=='(')
ok = false;
}
if(j<n && j!=i+1 && ok)
ans++;
}
}
cout << ans << '\n';
}
int32_t main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int tc=1;
cin >> tc;
for(int ttc=1;ttc<=tc;ttc++)
solve(ttc);
return 0;
}
Editorialist's code (Method 1 - Python)
for _ in range(int(input())):
n = int(input())
s = input()
reduced = ''
for c in s:
if not reduced or c != reduced[-1]: reduced += c
ans = 0
for i in range(len(reduced)):
if i+3 > len(reduced): break
ans += reduced[i:i+3] == ':):'
print(ans)