PROBLEM LINK:
Author: Arpit Kesharwani
Tester: Anshu Garg
Editorialist: Arpit Kesharwani
DIFFICULTY:
MEDIUM
PREREQUISITES:
String, Math
PROBLEM:
Given a binary string S, in one operation we can select any substring of size M and flip all its characters. There are Q queries and we can append a 0 or 1 character at the beginning of S in each query, what is the minimum number of operations required to make the string lexicographically minimum after each query.
EXPLANATION:
Below is a simple algorithm to find the minimum number of moves for each query by making the string lexicographically minimum :
– Iterate over string as: for i from 1 to |S|-m+1 (from MSB to LSB)
– If S[i] = 1 then flip all S[j] for j in [i,i+m-1] (all m bits) and add 1 to the ans.
This solution will be too slow ( Time Complexity: O(N*Q)), but the idea will be helpful to reach the actual solution. Before we move to actual solution let’s define few terms:
– s_i = i^{th} character of string S
– g_i=1 if the i^{th} bit of the string will be flipped
– x_i = \oplus(s_t) such that i\%m = t\%m and t \le i.
We will append Q zeroes to the beginning of S initially and will update them with query, we can see from the above algorithm that appending 0's to the beginning of string doesn’t affect the answer.
Now,
g_i = s_i \oplus (g_{i-1}\oplus g_{i-2} \oplus ...\oplus g_{i-m+1}) , \ \ i\le n+1-m
\implies g_{i-1}= s_{i-1} \oplus (g_{i-2}\oplus g_{i-2} \oplus ...\oplus g_{i-m})
\therefore \ \ g_i \oplus g_{i-1} = s_i\oplus s_{i-1}\oplus g_{i-m}\oplus g_{i-1}
\implies g_i = s_i\oplus s_{i-1}\oplus g_{i-m}
Similarly expanding the term g_{i-m},
g_{i-m}=s_{i-m}\oplus s_{i-m-1}\oplus g_{i-2m}
\therefore \ \ g_i=(s_i\oplus s_{i-m}\oplus ...\oplus s_{i-rm})\oplus (s_{i-1}\oplus s_{i-m-1}\oplus ...\oplus s_{i-rm-1})\oplus g_{i-(r+1)m}
If we expand this to the last term we get:
g_i = x_i\oplus x_{(i-1)}
Now the answer to the each query will be sum of all g_i's.
As stated earlier we had appended Q zeroes to the beginning of S initially and will update them with query.
Handling update part can be done as follows:
Let the index of string where update happens be cur\_idx.
If 0 is appended to the front of string then no change is observed in any of the g_i.
If 1 is appended to the string the g_i value of all positions i, such that:
- i \geq cur\_idx and
-
i\%m = cur\_idx\%m or (i+1)\%m = (cur\_idx)\%m
is flipped.
As we need sum of all g_i and as cur\_idx decreases with queries, we can store the required information to handle queries in the following arrays:
- total[0..m-1]: total[r] stores number of index i such that i\%m = r and i \geq cur\_idx
- plus[0...m-1]: plus[r] stores number of index i such that i\%m = r and i \geq cur\_idx and g_i=1.
SOLUTIONS:
Setter's Solution
#include<bits/stdc++.h>
using namespace std ;
void solve() {
int n,m,q;
cin >> n >> m >> q;
string s, cur_s;
cin >> s;
int x[q];
for(int i=0;i<q;++i) {
cin >> x[i];
cur_s += '0';
}
cur_s += s;
vector<int> X(m), tot(m), plus(m);
for(int i=q;i+m-1<cur_s.size();++i) {
X[i%m] ^= (cur_s[i] == '1');
tot[i%m]++;
int v = X[i%m]^X[(i-1+m)%m];
if(v == 1) plus[i%m]++;
}
int ans = 0;
for(int i=0;i<m;++i) ans += plus[i];
for(int i=0,cur_idx=q-1;i<q;++i,cur_idx--) {
if(x[i] == 1) {
int t = cur_s.size()-1, r = cur_idx%m;
tot[r]++;
int neg = tot[r] - plus[r] ;
ans += neg - plus[r];
plus[r] = neg;
r = (r+1)%m;
neg = tot[r] - plus[r];
ans += neg - plus[r];
plus[r] = neg;
} else tot[cur_idx%m]++;
cout << ans << '\n';
}
}
int main() {
int t;
cin >> t;
while(t--) solve();
}
Tester's Solution
#include<bits/stdc++.h>
using namespace std ;
#define ll long long
#define pb push_back
#define all(v) v.begin(),v.end()
#define sz(a) (ll)a.size()
#define F first
#define S second
#define INF 2000000000000000000
#define popcount(x) __builtin_popcountll(x)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define ld long double
template<typename T, typename U> static inline void amin(T &x, U y){ if(y < x) x = y; }
template<typename T, typename U> static inline void amax(T &x, U y){ if(x < y) x = y; }
int _runtimeTerror_()
{
int n, m, Q;
cin >> n >> m >> Q;
string s;
cin >> s;
vector<int> a(m), b(m);
a[(n - m) % m] += s[n - m] == '0';
b[(n - m) % m] += s[n - m] == '1';
int ans = b[(n - m) % m];
for(int i=n-m-1;i>=0;--i) {
int cur = s[i] - '0';
int f = i % m;
ans -= b[f];
if(cur) {
swap(a[f], b[f]);
++b[f];
}
else {
++a[f];
}
ans += b[f];
f = (f + 1) % m;
if(cur) {
ans -= b[f];
swap(a[f], b[f]);
ans += b[f];
}
}
int i = -1, prev = s[0] - '0';
for(int id=1;id<=Q;++id) {
i = (i + m) % m;
ans -= b[i];
int cur;
cin >> cur;
if(cur) {
swap(a[i], b[i]);
++b[i];
}
else {
++a[i];
}
ans += b[i];
int f = (i + 1) % m;
if(cur) {
ans -= b[f];
swap(a[f], b[f]);
ans += b[f];
}
--i;
cout << ans << "\n";
}
return 0;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int TESTS;
cin >> TESTS;
while(TESTS--) {
_runtimeTerror_();
}
return 0;
}