Skip to content

Commit e3483c1

Browse files
Create XOR Triangle Explanation.txt
1 parent 3f74b4e commit e3483c1

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
1. Fact - A triangle is good only if the pairwise AND is non-0.
2+
3+
Proof - x+y = x^y + 2(x&y)
4+
5+
x^y counts all bits which are set either in x or y.
6+
x&y counts all bits which are set in both x and y and therefore needs to be multiplied by 2.
7+
8+
We also know that if x, y and z form a triangle, then x + y > z
9+
10+
Let the integers we choose be (a, b, c)
11+
12+
(a^b) + (b^c) = (a^b^b^c) + 2[(a^b)&(b^c)] =
13+
(a^b) + (b^c) = (a^c) + 2[(a^b)&(b^c)]
14+
15+
(a^b) + (b^c) > (a^c) => (a^b)&(b^c) > 0
16+
17+
We can prove this cyclically for all 3 variables.
18+
19+
-----
20+
21+
We have an easier task now.
22+
We now have to count the nummber of integers (a, b, c) such that 1 <= a, b, c <= n and
23+
24+
1. (a^b)&(b^c) > 0
25+
2. (b^c)&(c^a) > 0
26+
3. (c^a)&(a^b) > 0
27+
28+
We will use Digit DP with the observation that all of a, b and c will match some prefix of n (possibly of length 0).
29+
30+
-----
31+
32+
We will represent the triplet as T[0], T[1], T[2] for convenience instead of (a, b, c).
33+
34+
The state of the DP is f(i, prefix_mask, condition_mask).
35+
This represents the number of triplets of consisting of the bits [0, i - 1] of N satsifying the two masks.
36+
The reason we are using i to represent the triplets ending with [i - 1] bits is because the string is 0-indexed.
37+
It might have been more intuitive if it were 1-indexed.
38+
39+
Here is the elaborate meaning of each variable.
40+
41+
1. i represents the bit of n where we are at now.
42+
2. prefix_mask is a mask of 3 bits represnting whether each member of the triplet
43+
is either = or less than the prefix of [0, i - 1]
44+
3. condition_mask is a mask of 3 bits reprsenting which of 3 conditions is already true in the prefix of length [0, i - 1]
45+
46+
Elaborating on how the masks are created.
47+
Let us suppose
48+
1. The first [0, i - 1] of T[0] match the first [0, i - 1] bits of N
49+
2. The first [0, i - 1] of T[1] is smaller than N
50+
3. The first [0, i - 1] of T[2] match the first [0, i - 1] bits of N
51+
52+
The prefix mask is 101
53+
54+
The condition mask is also similar. A mask of 110 means two of the conditions required for being a good triangle are satisfied.
55+
-----
56+
57+
This is a DP where it is easier to calculate the states f(i + 1, _, _) which f(i, _, _) will contribute to then
58+
build f(i, _, _) from f(i - 1, _, _)
59+
60+
We will iterate over all possibilities of the i-th bit of T[0], T[1], T[2]
61+
62+
If the first [0, i - 1] bits of N are equal to the first [0, i - 1] bits of T[0], the i-th bit of T[0] can only be [0, N[i]]
63+
If the first [0, i - 1] bits of N are smaller than the first [0, i - 1] bits of T[0], the i-th bit of T[0] can be both 0 or 1.
64+
65+
Recalculate the new prefix_mask and new condition_mask and accordingly do
66+
67+
f(i + 1, new_prefix_mask, new_condition_mask) += f(i, prefix_mask, condition_mask)
68+
69+
-----
70+
71+
Let us discuss the base case and the final answer
72+
73+
Let the base case be f(0, 111, 0) = 1
74+
75+
When we consider the empty string, it is not possible for a, b, c to be < N so the prefix mask has to be 111 only.
76+
None of the conditions are met so the condition mask be 0
77+
78+
The empty string N corresponds to prefix 111 and condition 0.
79+
80+
f(0, _, _) = 0 for all other values.
81+
82+
----
83+
84+
The final answer is when all the bits are used so i = N.size()
85+
The prefix mask can be any legal value
86+
The condition mask is 111
87+
88+
Answer = Sum f(N.size(), p, 111) over all legal values of prefix_mask
89+
90+
91+
------
92+
93+
Time limit is tight so do some language level optimizations like global arrays.
94+
95+
------
96+
97+
98+
int is_bit_set(int n, int bit)
99+
{
100+
return ( (n&(1 << bit)) != 0 );
101+
}
102+
103+
int main()
104+
{
105+
ios::sync_with_stdio(false);
106+
cin.tie(nullptr);
107+
108+
string S;
109+
cin >> S;
110+
111+
no_of_triplets[0][MAX_MASK][0] = 1;
112+
for(int i = 0; i < S.size(); i++)
113+
{
114+
int prefix = i - 1;
115+
for(int prefix_match = 0; prefix_match <= MAX_MASK; prefix_match++)
116+
{
117+
for(int condition_met = 0; condition_met <= MAX_MASK; condition_met++)
118+
{
119+
for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++)
120+
{
121+
limit[bit] = (is_bit_set(prefix_match, bit) ? S[i] : '1') - '0';
122+
}
123+
124+
for(next_bit[0] = 0; next_bit[0] <= limit[0]; next_bit[0]++)
125+
{
126+
for(next_bit[1] = 0; next_bit[1] <= limit[1]; next_bit[1]++)
127+
{
128+
for(next_bit[2] = 0; next_bit[2] <= limit[2]; next_bit[2]++)
129+
{
130+
131+
for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++)
132+
{
133+
triangle_sides[bit] = next_bit[bit]^next_bit[(bit + 1)%NO_OF_TRIANGLE_SIDES];
134+
}
135+
136+
int next_prefix_match = 0;
137+
for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++)
138+
{
139+
if(is_bit_set(prefix_match, bit) && next_bit[bit] == S[i] - '0')
140+
{
141+
next_prefix_match |= (1 << bit);
142+
}
143+
}
144+
145+
int next_condition_met = 0;
146+
for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++)
147+
{
148+
int condition_here = (triangle_sides[bit]&triangle_sides[(bit + 1)%NO_OF_TRIANGLE_SIDES] != 0);
149+
if(is_bit_set(condition_met, bit) || condition_here)
150+
{
151+
next_condition_met |= (1 << bit);
152+
}
153+
}
154+
155+
no_of_triplets[i + 1][next_prefix_match][next_condition_met] += no_of_triplets[i][prefix_match][condition_met];
156+
no_of_triplets[i + 1][next_prefix_match][next_condition_met] %= MOD;
157+
158+
/*cout << "F(" << i + 1 << "," << next_prefix_match << "," << next_condition_met << ") = "
159+
<< no_of_triplets[i + 1][next_prefix_match][next_condition_met] << " added "
160+
<< "F(" << i << "," << prefix_match << "," << condition_met << ") = "
161+
<< no_of_triplets[i][prefix_match][condition_met] << " Current "
162+
<< next_bit[0] << " " << next_bit[1] << " " << next_bit[2] << "\n";*/
163+
}
164+
}
165+
}
166+
}
167+
}
168+
}
169+
170+
long long answer = 0;
171+
for(int prefix_match = 0, all_conditions_met = MAX_MASK; prefix_match <= MAX_MASK; prefix_match++)
172+
{
173+
answer += no_of_triplets[S.size()][prefix_match][all_conditions_met];
174+
answer %= MOD;
175+
}
176+
177+
cout << answer << "\n";
178+
return 0;
179+
}

0 commit comments

Comments
 (0)