This is the harder version of the problem I previously discussed here.
Problem CF-2056F2
Statement
A sequence
of integers is called good iff the following condition holds:
- Let
be the number of occurrences of in the sequence . - For all pairs
, at least one of the following must be true:
In other words, if both
and are present in the sequence, then the number of occurrences of must be less than or equal to the number of occurrences of . You are given integers
and . Compute the bitwise XOR of the medians of all good sequences of length , where each element satisfies .
Constraints:
(given to us in its binary form)
Solution
I'm going to pick up right where I left off in the previous blog.
Notice the changes in this version - the constraints on
Let's examine the algorithm we used earlier at a high level, and see if there are components vulnerable to optimization:
ans = 0
for median q from 0 to m - 1:
par = 0
for (# of unique elements) x from 1 to min(q + 1, k):
if (C(q, x - 1) * f(k, x)) % 2 == 1
par ^= 1
if par == 1
ans ^= q
Firstly, we cannot compute required values of
Now, as we already know from the ideas introduced in the previous blog:
ans = 0
for median q from 0 to m - 1:
par = 0
for submask x of q such that x < k:
par ^= f(k, x + 1)
if par == 1
ans ^= q
It should not be difficult to spot some glaring redundancy here, namely the fact that
Why is this the case? Notice that while
To avoid this redundancy, we can instead compute the value of
Our algorithm now reduces to the following:
ans = 0
for (median suffix mask) p from 0 to (2^L - 1):
par = 0
for submask x of p:
par ^= f(k, x + 1)
if par == 1
ans ^= (q : (the first L bits of q = p))
Now, the problem decomposes to two easy and independent subproblems:
- Finding
(here means that is a submask of ). This is a standard application of SOS DP, and warrants no further explanation from me. - Finding
. This can be done in but I hate digit analysis far too much to not have mindlessly bashed it in .
So our final solution runs in
Code:
#include<bits/stdc++.h>
using namespace std;
signed main()
{
ios_base::sync_with_stdio(false), cin.tie(NULL);
int t = 1;
cin >> t;
while(t --)
{
int k, m;
cin >> k >> m;
string n;
cin >> n;
k = count(n.begin(), n.end(), '1');
int L = 0;
while((1 << (L)) <= k)
++ L;
auto f = [&](int a, int b) -> int
{
if(a < b)
return 0;
return ((a - b) & ((b - 1) >> 1)) == 0;
};
vector<int> sos(1 << L);
for(int p = 0; p < (1 << L); p ++)
sos[p] = f(k, p + 1);
for(int i = 0; i < L; i ++)
for(int p = 0; p < (1 << L); p ++)
if((1 << i) & p)
sos[p] ^= sos[p ^ (1 << i)];
int ans = 0;
for(int p = 0; p < (1 << L); p ++)
{
if(sos[p])
if(p < m)
{
int xorsum = 0;
// p0 p1 ... p(L-1) bit(L) bit(L+1) ...
for(int b = L; b < 30; b ++)
if((1 << b) + p < m)
{
vector<int> bits;
for(int i = L; i < 30; i ++)
if(i != b)
bits.push_back(i);
int sz = bits.size();
int l = 0, r = (1 << sz) - 1, opt = 0;
while(l <= r)
{
int mid = (l + r)/2;
int sum = (1 << b) + p;
for(int i = 0; i < bits.size(); i ++)
if((1 << i) & mid)
sum += (1 << bits[i]);
if(sum < m)
opt = mid, l = mid + 1;
else
r = mid - 1;
}
if((opt + 1) & 1)
xorsum ^= (1 << b);
}
{
vector<int> bits;
for(int i = L; i < 30; i ++)
bits.push_back(i);
int sz = bits.size();
int l = 0, r = (1 << sz) - 1, opt = 0;
while(l <= r)
{
int mid = (l + r)/2;
int sum = 0;
for(int i = 0; i < bits.size(); i ++)
if((1 << i) & mid)
sum += (1 << bits[i]);
if(sum + p < m)
opt = mid, l = mid + 1;
else
r = mid - 1;
}
if((opt + 1) & 1)
xorsum ^= p;
}
ans ^= xorsum;
}
}
cout << ans << endl;
}
}