Atto Round 1 (Codeforces Round 1041, Div. 1 + Div. 2) Editorial

By Bahamin, 20 hours ago,

Hope you enjoyed the problems!

2127A - Mix Mex Max

Idea: Bahamin
Preparation: Hamed_Ghaffari

Hints

Hint 1

What happens if mex([ai,ai+1,ai+2])=0\operatorname{mex}([a_i, a_{i+1}, a_{i+2}]) = 0?

Hint 2

Now what happens if mex([ai,ai+1,ai+2])0\operatorname{mex}([a_i, a_{i+1}, a_{i+2}]) \neq 0?

Solution

Let’s see when does mex([ai,ai+1,ai+2])\operatorname{mex}([a_i, a_{i+1}, a_{i+2}]) equal max([ai,ai+1,ai+2])min([ai,ai+1,ai+2])\max([a_i, a_{i+1}, a_{i+2}]) - \min([a_i, a_{i+1}, a_{i+2}]).

Case 1: mex([ai,ai+1,ai+2])=0\operatorname{mex}([a_i, a_{i+1}, a_{i+2}]) = 0

This implies that all numbers are equal and non-zero, since otherwise min\min would be less than max\max and the difference wouldn’t be 00.

Case 2: mex([ai,ai+1,ai+2])0\operatorname{mex}([a_i, a_{i+1}, a_{i+2}]) \neq 0

In this case min([ai,ai+1,ai+2])\min([a_i, a_{i+1}, a_{i+2}]) should be 00 because 00 is in the sequence. So mex([ai,ai+1,ai+2])=max([ai,ai+1,ai+2])\operatorname{mex}([a_i, a_{i+1}, a_{i+2}]) = \max([a_i, a_{i+1}, a_{i+2}]) but this is not possible, since mex([ai,ai+1,ai+2])\operatorname{mex}([a_i, a_{i+1}, a_{i+2}]) should not be among aia_i, ai+1a_{i+1}, or ai+2a_{i+2}.

So an array is good if all elements are equal and non-zero. Remove every 1-1 from aa, then check whether all remaining elements are equal and non-zero.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <bits/stdc++.h>

using namespace std;

int main() {
int tc;
cin >> tc;
while (tc--) {
int n;
cin>>n;
vector<int> v(n);
for (int i = 0; i < n; i++) cin >> v[i];
set<int> s(v.begin(), v.end());

s.erase(-1);
if (s.size()<=1 && !s.count(0)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}

2127B - Hamiiid, Haaamid… Hamid?

Idea: _R00T and Error_Yuan
Preparation: _R00T and Hamed_Ghaffari

Hints

Hint 1

The answer to the problem only depends on xx, nn, the index of the wall Hamid would hit if he moves to the left, and the index of the wall he would hit if he moves to the right.

Hint 2

If we denote the two indices defined in Hint 1 as LL and RR, then in each of Hamid’s turns, he can move in a way that ensures by the next time, either LL has decreased by at least one, or RR has increased by at least one, regardless of Mani’s moves. So, if it’s Hamid’s turn, what is the maximum possible answer in terms of LL, RR, and nn?

Answer

The answer is at most min(L+1,nR+2)\min(L + 1, n - R + 2).

Solution

Suppose it’s Hamid’s turn. If there is no wall to his right or to his left, he can escape the grid in one move. Otherwise, define:

  • LL as the index of the wall Hamid would reach if he moves to the left.
  • RR as the index of the wall he would reach if he moves to the right.

Hamid can move to the left and decrease LL by at least one. (Since LL is always to the left of Hamid’s current position, when Hamid moves left, he reaches and destroys the wall at position L. As a result, on his next turn, the new L will be at least one position further to the left. meaning LL decreases by at least one, regardless of Mani’s actions.) Similarly, Hamid can increase RR by at least 11 by moving to the right and destroying the wall there.

So, since Hamid wants to escape in the minimum number of moves, he can escape the grid in at most min(L+1,nR+2)\min(L + 1, n - R + 2) moves.

On the other hand, with each of Hamid’s moves, Mani can place a wall in such a way that LL decreases by at most one or R increases by at most one.

So the minimum number of moves Hamid needs is also min(L+1,nR+2)\min(L + 1, n - R + 2).

Therefore, assuming Hamid starts first, the answer is min(L+1,nR+2)\min(L + 1, n - R + 2).

Now consider Mani’s first move. Since Mani wants to maximize the number of days Hamid needs. Moreover, with each of his moves, at least one of the LL or RR remains unchanged. So, on his first move, he can:

  • maximize L+1L + 1 by setting L=x1L = x - 1, or
  • maximize nR+2n - R + 2 by minimizing RR, setting it to x+1x + 1.

So the answer becomes either min((x1)+1,nR+2)\min((x-1) + 1, n - R + 2) or min(L+1,n(x+1)+1)\min(L + 1, n - (x+1) + 1).

Because Mani wants the number of days to be as large as possible, the final answer is: max(min(x,nR+2),min(L+1,nx+1))\max(\min(x, n - R + 2), \min(L + 1, n - x + 1))

We can easily find L and R with a time complexity of O(n)\mathcal{O}(n). Therefore, the problem is solved in O(n)\mathcal{O}(n) time complexity.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<bits/stdc++.h>
using namespace std;

int32_t main() {
cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);
int tc;
cin >> tc;
while(tc--) {
int n, x;
string s;
cin >> n >> x >> s;
if(x==1 || x==n) {
cout << "1\n";
continue;
}
x--;
int inf = 1e9;
int lf=-inf, rg=inf;
for(int i=x-1; i>=0; i--)
if(s[i]=='#') {
lf=i;
break;
}
for(int i=x+1; i<n; i++)
if(s[i]=='#') {
rg=i;
break;
}
if(lf==-inf && rg==inf) {
cout << "1\n";
continue;
}
cout << max(min(x+1, n-rg+1), min(lf+2, n-x)) << '\n';
}
return 0;
}

2127C - Trip Shopping

Idea: Bahamin
Preparation: Bahamin and _R00T

Hints

Hint 1

We can see that permuting arrays aa and bb in the same way or changing aia_i with bib_i for a specific index ii doesn’t change the answer. WLOG assume aibia_i \leq b_i is always true.

Hint 2

Imagine Ali selects indices ii and jj in a round of game. What are all the different new arrays Bahamin can achieve?

Can Ali ever achieve a valuevalue less that the initial valuevalue?

Answer

He can’t. Because Bahamin can always keep the chosen indices as they are, and so the valuevalue won’t change. No matter what Ali does.

Solution

Read the hints.

Let’s first address hint 22. To determine all arrays that Bahamin can reach, WLOG assume aibiajbja_i \leq b_i \leq a_j \leq b_j. The specific order doesn’t matter, since Bahamin can permute them freely. Set x1=aix_1 = a_i, x2=bix_2 = b_i, x3=ajx_3 = a_j, x4=bjx_4 = b_j — this makes the following cases reachable for Bahamin:

  1. ai:=x1,bi:=x2,aj:=x3,bj:=x4 value=x2x1+x4x3a_i := x_1, b_i := x_2, a_j := x_3, b_j := x_4 \rightarrow \space value = x_2 - x_1 + x_4 - x_3
  2. ai:=x1,bi:=x3,aj:=x2,bj:=x4 value=x3x1+x4x2a_i := x_1, b_i := x_3, a_j := x_2, b_j := x_4 \rightarrow \space value = x_3 - x_1 + x_4 - x_2
  3. ai:=x1,bi:=x4,aj:=x2,bj:=x3 value=x4x1+x3x2a_i := x_1, b_i := x_4, a_j := x_2, b_j := x_3 \rightarrow \space value = x_4 - x_1 + x_3 - x_2

Other cases are similar (based on Hint 11). We observe that the second and third options yield the same valuevalue, while the first option is exactly 2×(x3x2)2 \times (x_3 - x_2) less than the other two. There are now two possible cases:

Case 1: Ali can choose two indices ii and jj such that the ordering of [ai,bi,aj,bj][a_i, b_i, a_j, b_j] already matches one of the second or third options. In this case, Bahamin cannot increase the value when he is initially given indices ii and jj. Since Ali also cannot reduce the valuevalue, his optimal strategy is to always give Bahamin such indices so that the final valuevalue remains equal to the initial valuevalue.

Case 2: Ali cannot find any two indices ii and jj that match the second or third option. This implies that for every pair of indices i,ji, j, either b_i &lt; a_j or b_j &lt; a_i. We claim the answer is \sum\limits_{i=1}^{n} (b_i - a_i) + \min\limits_{1 \leq i, j \leq n, \space b_i &lt; a_j} (2 \times (a_j - b_i)).

A strategy for Ali is to always select the two indices i,ji, j such that b_i &lt; a_j and the difference ajbia_j - b_i is minimized. Bahamin can increase the valuevalue only once — when he changes the configuration of indices i,ji, j from the first option to either the second or third option. We know this increases the initial valuevalue by exactly 2×(ajbi)2 \times (a_j - b_i). Also, it’s impossible for Ali to force any valuevalue lower than this. Since regardless of Ali’s selection, Bahamin can always change it to the second or third option, and by definition, any choice by Ali gives Bahamin a chance to increase valuevalue by at least our claimed amount. Also Bahamin should skip his turn (i.e., make no changes) on all subsequent turns after the first.

Now to calculate the answer so that it fits the time limit, let’s first represent our array as a set of nn segments of the form [ai,bi][a_i, b_i] on the number line. An interesting property of this representation is that the first option now corresponds to two completely separate intervals, while the second and third options correspond to two intersecting intervals.

Now finding the answer becomes relatively easy. Sort the intervals by their left endpoint. If there are two neighboring intervals that intersect, then the input satisfies the Case 1 condition, and so the answer is the initial valuevalue. Otherwise, we observe that all pairs of intervals are non-intersecting, and thus the input satisfies the Case 2 condition. The answer, based on Case 2 and our earlier definitions, is 2×(distance between closest two segments)+(initial value)2 \times (\text{distance between closest two segments}) + (\text{initial value}).

The two closest intervals must also be adjacent after sorting by their left endpoint. So, by computing the minimum distance between each pair of neighboring intervals, we obtain a solution in O(nlogn)\mathcal{O}(n \log n).

Code

Bonus

There were completely different versions of this problem at first.

The original version was that Ali and Bahamin would take turns, and on each turn, a player would perform both operations described in the problem. Their goals and the constraints were similar to what is stated in the final version of the question.

Can you solve it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>
using namespace std;

const int MXN = 2e5+5;

int n, k, a[MXN];

void Main() {
cin >> n >> k;
for(int i=1; i<=n; i++) cin >> a[i];
vector<pair<int, int>> vec;
long long ans = 0;
for(int i=1, b; i<=n; i++) {
cin >> b;
if(b<a[i]) swap(b, a[i]);
ans += b-a[i];
vec.push_back({a[i], b});
}
sort(vec.begin(), vec.end());
for(int i=1; i<n; i++)
if(vec[i].first<=vec[i-1].second) {
cout << ans << '\n';
return;
}
int mn = 2e9;
for(int i=1; i<n; i++)
mn = min(mn, vec[i].first - vec[i-1].second);
cout << ans + 2*mn << '\n';
}

int32_t main() {
cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);
int tc;
cin >> tc;
while(tc--) Main();
}

2127D - Root was Built by Love, Broken by Destiny

Idea: _R00T and Bahamin
Preparation: _R00T and Hamed_Ghaffari

Hints

Hint 1

We can prove that the map of Destinyland contains no cycles.

Hint 2

Take a look at the map below:

Hint 3

Prove that a tree can be a valid Destinyland map if and only if it does not contain a subtree that looks like the one shown in Hint 2.

Hint 4

If we remove all the leaves from the Destinyland tree, the remaining graph forms a simple path.

Solution

Let GG be the graph of the Destinyland map.

If there exists a subgraph HH of GG that cannot be a valid Destinyland map, then GG itself cannot be valid either.

To prove this, assume, for contradiction, that GG is valid but HH is not. Then, by removing the vertices and edges not in HH, we get a subgraph HH that should also be valid. But it isn’t! This contradicts our assumption, so GG cannot be valid either.

Lemma 1: A cycle of any length cannot be a valid Destinyland map.
Proof: Assume the opposite. Let vv be the leftmost house on the northern side. It has two neighbors on the southern side. Let the one on the left be LL and the other one RR. Since LL must have another neighbor besides vv, that neighbor cannot be on the southern side, so it must be on the northern side. However, since vv is the leftmost node, this neighbor must be to the right of vv, and the edge between LL and this neighbor would cross the edge vvLL. This contradiction shows that LL cannot have another neighbor besides vv, which contradicts our assumption that the graph is a cycle.

Lemma 2: The following tree cannot be a valid Destinyland map:

Proof: Vertices 22, 33, and 44 are all on the side opposite vertex 11. If we place them in order from left to right as u1u_1, u2u_2, and u3u_3, then the neighbor of u2u_2 will necessarily create a crossing either with edge 11u1u_1 or 11u3u_3. Therefore, it is impossible to arrange the vertices of this tree in a valid Destinyland layout.

From Lemma 1 and Lemma 2, we conclude that:

  • GG must be a tree.
  • No vertex in GG can be connected to three or more non-leaf neighbors.

Now, remove all the leaf nodes. Since these leaves are always non-cut vertices (i.e., their removal doesn’t disconnect the tree), the remaining graph, if it exists, is still connected. Since all remaining vertices have degree at most 22. So the resulting structure must be a path.

Case 1: The graph becomes empty after removing leaves.
In this case, the original graph was just a single edge. So the answer is simply 22.

Case 2: Only one vertex remains.
In this case, the original tree was a star. Depending on which side we place the central vertex, and how we permute the leaves, the answer is: 2×(n1)!2\times(n−1)!

Case 3: Two connected non-leaf vertices uu and vv remain.
In this case, there are 44 valid placements depending on which one is on the northern side and how their adjacent leaves are arranged around the other. ( Note: It’s impossible for either uu or vv to have neighbors on both sides of the other.)
So the answer is: 4×(du1)!×(dv1)!4\times(d_u−1)!\times(d_v−1)! where dud_u and dvd_v are the degrees of uu and vv, respectively.

Case 4: The remaining structure is a path of length at least 33.
In this case, we have 44 valid ways to place it. These depend on which vertices are placed on the northern side, and how the two vertices from one side with at least two vertices are positioned. (Since the path has at least 33 vertices, there’s no conflict.)

Now, we only need to arrange the leaves adjacent to each vertex relative to each other. Because their positions relative to the other vertices depend only on the four ways to arrange the main path. The proof of that is boring, so we won’t bore you with it :)

Let SS be the set of vertices on the path, and let SahaiSaha_i be the number of leaves connected to vertex ii. Then the total number of valid layouts is: 4×rS(Sahar!)4 \times \prod\limits_{r \in S} (Saha_r!)

To implement the solution:

  1. Check if the input graph is a tree.
  2. Verify that no vertex has more than two non-leaf neighbors.
  3. Count the number of non-leaf vertices.
  4. Based on that count, determine which case applies and compute the answer accordingly.

The entire algorithm runs in O(n)\mathcal{O}(n) time.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;

#define SZ(x) int(x.size())

const int MOD = 1e9 + 7;
const int MXN = 2e5 + 5;

int n, m, fact[MXN];
vector<int> adj[MXN];

int32_t main() {
cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);
fact[0] = 1;
for (int i = 1; i < MXN; i++)
fact[i] = (1ll * fact[i-1] * i) % MOD;
int T;
cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) adj[i].clear();
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}

long long ans = 2;
int tl = 0;
if (m >= n) ans = 0;
for (int u = 1; u <= n; u++) {
if (adj[u].size() > 1) {
int x = 0;
for (int v : adj[u]) {
x += (SZ(adj[v]) == 1);
}
if (x >= SZ(adj[u]) - 2) (ans *= fact[x]) %= MOD;
else ans = 0;
} else tl ++;
}
if (tl < n-1) tl = 2; else tl = 1;
cout << (ans * tl % MOD) << '\n';
}
return 0;
}

2127E - Ancient Tree

Idea: Bahamin
Preparation: Bahamin and Hamed_Ghaffari

Hints

Hint 1

There are some vertices that will always be cutie, no matter how the other vertices are colored. What are these vertices?

Hint 2

We can show that there exists a coloring where only the vertices mentioned in Hint 1 become cutie. So, the final answer is the sum of the weights of the vertices mentioned in Hint 1.

Solution

Read the hints.

We will use a very useful and interesting technique called the Virtual Tree (or Auxiliary Tree). You can learn more here: Virtual Tree. There are other solutions to this problem, but they use a similar core idea.

The virtual tree of a set of vertices like SS is defined as this set:

A=S{lca(u,v)u,vS}A = S \cup \{\operatorname{lca}(u, v) \mid u, v \in S \}

Now let’s build this virtual tree for the vertices of each color separately. After this, all vertices fall into three categories:

  1. Vertices that are in no virtual tree.
  2. Vertices that are in exactly one virtual tree.
  3. Vertices that appear in more than one virtual tree.

Every vertex like uu of the third type will definitely be cutie, because no matter what color it is assigned, at least one of the colors of the virtual trees it belongs to will be different from uu's color.

So the answer is at least the sum of the weights of all type-3 vertices.

To construct an example with exactly this answer, run a DFSDFS algorithm. Every time you enter a vertex uu, consider the following cases:

  • It’s type 2. In that case, color it with the color of the virtual tree it belongs to.
  • It’s type 3. In that case, color it with any color from its subtree (such a color exists by definition). This vertex is cutie anyway.
  • It’s type 1 and there is some colored vertex in its subtree. Then color this vertex with that color.
  • It’s type 1 and its entire subtree is uncolored. In that case, color this vertex with its parent’s color.

To prove this coloring is valid, observe that coloring a vertex uu with a color from its subtree does not make any new vertices cutie (because any such vertex would already have become cutie due to the same color in uu's subtree). Also, no vertex strictly inside uu's subtree changes status. And uu itself doesn’t increase the cost based on how we chose its color.

Now, for the case where we color uu with its parent’s color: if any new cutie vertex appears, it must be the parent. But since both have the same color, there’s no additional cost.

Also, in this constructed example, we never introduce any new colors. So all colors stay within the range [1,k][1, k].

Therefore, the final answer is always the sum of the weights of type-3 vertices—those that appear in more than one virtual tree. These virtual trees can be constructed in O(nlogn)\mathcal{O}(n \log n).

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

const int MXN = 2e5+1, LOG = 18;

int n, k, w[MXN], c[MXN], par[LOG][MXN], stt[MXN], timer, h[MXN], cnt[MXN], col[MXN];
vector<int> g[MXN], cols[MXN];
bool mark[MXN], cutie[MXN];

void dfs(int v) {
stt[v] = timer++;
for(int i=1; i<LOG; i++) par[i][v] = par[i-1][par[i-1][v]];
for(int u : g[v])
if(u!=par[0][v]) {
h[u] = h[v]+1;
par[0][u] = v;
dfs(u);
}
}

inline int jump(int v, int d) {
for(int i=0; i<LOG; i++)
if(d>>i&1)
v = par[i][v];
return v;
}

inline int LCA(int u, int v) {
if(h[u]<h[v]) swap(u, v);
u = jump(u, h[u]-h[v]);
if(u==v) return u;
for(int i=LOG-1; i>=0; i--)
if(par[i][u]!=par[i][v])
u = par[i][u], v = par[i][v];
return par[0][u];
}

void DFS(int v, int cc) {
if(c[v]) cc=c[v];
else c[v]=cc;
for(int u : g[v])
if(u!=par[0][v])
DFS(u, cc);
}

void Main() {
cin >> n >> k;
timer = 0;
for(int i=1; i<=n; i++) {
cnt[i] = 0;
col[i] = 0;
g[i].clear();
cutie[i] = 0;
cols[i].clear();
}
for(int i=1; i<=n; i++) cin >> w[i];
for(int i=1; i<=n; i++) cin >> c[i], cols[c[i]].push_back(i);
for(int i=1, u,v; i<n; i++) {
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
bool fnd=0;
for(int i=1; i<=n; i++)
fnd |= c[i];
if(!fnd) {
cout << "0\n";
for(int i=1; i<=n; i++) cout << "1 ";
cout << '\n';
return;
}
dfs(1);
for(int i=1; i<=k; i++) {
sort(cols[i].begin(), cols[i].end(), [&](int u, int v) {
return stt[u]<stt[v];
});
vector<int> V;
for(int j=0, u, v, lca; j+1<int(cols[i].size()); j++) {
u = cols[i][j], v = cols[i][j+1], lca = LCA(u, v);
if(!mark[lca]) {
if(c[lca]) {
if(c[lca] != i) cutie[lca] = 1;
continue;
}
mark[lca] = 1;
cnt[lca]++;
col[lca] = i;
V.push_back(lca);
}
}
for(int v : V) mark[v] = 0;
cols[i].clear();
}
ll val=0;
for(int i=1; i<=n; i++) {
if(cutie[i] || cnt[i]>1) val += w[i];
if(!c[i] && cnt[i]==1) c[i] = col[i];
}
cout << val << '\n';
for(int i=1; i<=n; i++)
if(c[i]) {
DFS(1, c[i]);
break;
}
for(int i=1; i<=n; i++) cout << c[i] << ' ';
cout << '\n';
}

int32_t main() {
cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);
int tc;
cin >> tc;
while(tc--) Main();
return 0;
}

2127F - Hamed and AghaBalaSar

Idea: Hamed_Ghaffari and _R00T
Preparation: Hamed_Ghaffari

Hints

Hint 1

What exactly is f(a)f(a)?

Answer

f(a)f(a) is the sum of maximums minus the sum of element right after a maximum minus a1a_1.

Hint 2

Fix the maximum. How to count the sum of maximums?

Hint 3

You need to solve the following sub-problem:

You are given three integers nn, mm, and xx. How many arrays a1,a2,,ana_1,a_2,\ldots,a_n exists such that:

  • 0aix0 \leq a_i \leq x for all 1in1 \leq i \leq n
  • a1+a2++an=ma_1 + a_2 + \ldots + a_n = m

Hint 4

The sub-problem can be solved in O(m/x)\mathcal{O}(m/x) using inclusion exclusion.

Hint 5

How to count the sum of an specific element in the sub-problem of Hint 3?

Solution

Observation: f(a)f(a) is the sum of maximums minus the sum of element right after a maximum minus a1a_1.

Proof

Suppose that 1=i1<i2<<ik=n1 = i_1 \lt i_2 \lt \ldots \lt i_k = n is the indices that we visit in the algorithm, and 1j1<j2<<jt=k1 \leq j_1 \lt j_2 \lt \dots \lt j_t = k is the indices such that aijpa_{i_{j_p} } is maximum for all 1pt1 \leq p \leq t.

If we group the indices like below:

  • i1,,ij1i_1, \ldots, i_{j_1}

  • ij1+1,,ij2i_{j_1+1}, \ldots, i_{j_2}

  • ijt1+1,,iki_{j_{t-1}+1}, \ldots, i_k

each group will be increasing and f(a)f(a) will be:

(aij1ai1)++(anaijt1+1)=p=1taijpp=1t1aijp+1a1(a_{i_{j_1} }-a_{i_1}) + \ldots + (a_n - a_{i_{j_{t-1}+1} }) = \sum\limits_{p=1}^{t}a_{i_{j_p} } - \sum\limits_{p=1}^{t-1}a_{i_{j_p+1} } - a_1

Let g(n,m,x)g(n, m, x) be the answer of the sub-problem in Hint 3. We can calculate g(n,m,x)g(n, m, x) is O(m/x)\mathcal{O}(m/x) using inclusion exclusion and “Stars and bars”.

g(n,m,x)=t=0mx+1(1)t(nt)(m+n1t(x+1)n1)g(n, m, x) = \sum\limits_{t=0}^{\lfloor \frac{m}{x+1} \rfloor}{(-1)^t \binom{n}{t} \binom{m + n - 1 - t(x+1)}{n - 1} }

From now we fix an=xa_n = x and calculate the sum of f(a)f(a) over all snake arrays with maximum equal to xx.

Counting the sum of maximums:

The sum of ana_n over all arrays is xg(n1,mx,x)x \cdot g(n-1,m-x,x). The sum of aia_i for all 1in11 \leq i \leq n-1 such that ai=xa_i=x is x(n1)g(n2,m2x,x)x \cdot (n-1) \cdot g(n-2, m-2x, x).

Counting the sum of a1a_1:

Let sis_i be the sum of aia_i over all snake arrays with an=xa_n=x for all 1i<n1 \leq i \lt n.

It turns out that si=sjs_i = s_j for all 1i,j<n1 \leq i, j \lt n, because we can swap aia_i and aja_j in every array and there is no difference between ii and jj.

The sum of a1,a2,,an1a_1,a_2,\ldots,a_{n-1} in every snake array is mxm-x, so s1+s2++sn1=(mx)g(n1,mx,x) s1=mxn1g(n1,mx,x).s_1+s_2+\ldots+s_{n-1} = (m-x)g(n-1,m-x,x) \rightarrow \space s_1 = \frac{m-x}{n-1}g(n-1,m-x,x).

Counting the sum of elements right after a maximum:

This part is similar to a1a_1 part. Suppose that ai1=xa_{i-1}=x, the sum is (m2x)g(n2,m2x,x)(m-2x)g(n-2,m-2x,x) for all 1<i<n1 \lt i \lt n, and xg(n2,m2x,x)x \cdot g(n-2, m-2x,x) for i=ni=n.

Since for each xx we just need g(n1,mx,x)g(n-1, m-x, x) and g(n2,m2x,x)g(n-2, m-2x, x), the solution runs in x=0mmx+1=O(mlogm)\sum\limits_{x=0}^{m}{\frac{m}{x+1} } = \mathcal{O}(m\log m).

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

const int MXN = 4e5+5;
const int MOD = 1e9+7;

ll power(ll a, ll b) {
ll res = 1;
while(b) {
if(b&1) (res *= a) %= MOD;
(a *= a) %= MOD;
b >>= 1;
}
return res;
}

ll F[MXN], I[MXN];

void prep() {
F[0] = 1;
for(int i=1; i<MXN; i++) F[i] = F[i-1]*i%MOD;
I[0] = I[1] = 1;
for(int i=2; i<MXN; i++) I[i] = (MOD-MOD/i)*I[MOD%i]%MOD;
for(int i=2; i<MXN; i++) (I[i] *= I[i-1]) %= MOD;
}
ll C(int n, int r) {
return r<0 || r>n ? 0 : F[n]*I[r]%MOD*I[n-r]%MOD;
}
ll g(int n, int m, int l) {
if(n==0) return m==0;
ll ans = 0;
for(int t=0; t<=n && t*(l+1)<=m; t++)
(ans += C(n,t)*C(m+n-1-t*(l+1), n-1)%MOD*(t%2 ? MOD-1 : 1)%MOD) %= MOD;
return ans;
}

void solve() {
ll n, m, ans=0;
cin >> n >> m;
ll inv = power(n-1, MOD-2);
for(ll x=0; x<=m; x++) {
ll g1 = g(n-1, m-x, x), g2 = g(n-2, m-2*x, x);
(ans += x*(g1+g2*(n-1)%MOD)) %= MOD;
ll bad=0;
(bad += (m-x)*g1%MOD*inv) %= MOD;
(bad += x*g2) %= MOD;
(bad += (m-2*x)*g2) %= MOD;
(ans += MOD-bad) %= MOD;
}
cout << ans << '\n';
}

int32_t main() {
cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);
prep();
int tc;
cin >> tc;
while(tc--) solve();
return 0;
}

2127G1 - Inter Active (Easy Version)

Idea: Ali_BBN
Preparation: Hamed_Ghaffari and Ali_BBN

Hints

Step 0

Consider the following graph: ipii\to p_i. We will see the permutation as the graph.

When asking a permutation qq, the result is sum of whether q^{-1}(i)&lt;q^{-1}(p_i).

Hint 1

Why is there a condition about kk? If we do not have kk, can the permutation [2,1,4,3][2, 1, 4, 3] be guessed out?

Hint 2.1

When we ask a permutation, what does asking the reverse of the permutation help us with?

Hint 2.2

If we ask the reverse of the permutation except the index kk, how many times is each edge of the permutation graph counted in total?

Hint 3

How to choose kk?

Solution

Let xx be a number that we have not yet fixed, and let k=x+1k = x + 1.

This partitions the array into three segments:

$ \begin{aligned} A &= [1, x] \ B &= [x + 2, n - x] \ C &= [n - x + 1, n] \end{aligned}$

This tripartition helps in controlling the query behavior.

Queries:

Say we want to find out who maps to vertex ii, i.e., find jj such that pj=ip_j = i.

Here’s how:

  1. Construct a permutation qq such that qk=iq_k = i
  2. Query this permutation receive answer aa
  3. Reverse all elements of qq except the position kk
  4. Query the reversed permutation receive answer bb

If we consider the permutation graph of p:

  • Any edge not involving ii contributes once to the total count. Why?
  • The edge where pj=ip_j = i:
    • Will not be counted if j=qkj = q_k. This is not possible because it is guaranteed in the question that piip_i\neq i.
    • Will be counted in only one of the two queries if jq[AC]j \in q[A \cup C].
    • Will be counted neither if jq[B]j \in q[B].
  • The edge where pi=jp_i = j will not be counted at all, because ii is at index kk.

Thus, a+ba + b is one of [n2,n1][n - 2, n - 1] and by comparing a+ba + b, we can find which segment jj (the predecessor of ii) lies in.

Repeating the Process:

Once you know the predecessor is in a certain half, you repeat:

  • Repartition the candidate set into two
  • Choose one half to be placed in ACA \cup C, and the other in BB (If we had enough capacity).
  • Place ii at index kk again.
  • Do the same query + reverse trick

Choosing k:

If we set x=n+14,k=x+1x = \lfloor \frac{n+1}{4} \rfloor,\quad k = x + 1, with each iteration (both in the first query and in the rest of the queries) the size of the candidate set shrinks by a factor of 2.

So to find the predecessor of one number ii, we need 2log(n1)2 \log (n - 1) queries.

To find the entire permutation of nn elements 2nlog(n1)2 n\log (n - 1) queries.

We stay well within the 15n15 \cdot n limit.

Code

Bonus

This way can also be implemented with 2log(n1)+x=1n12logx12n2 \log (n - 1) + \sum\limits_{x=1}^{n - 1}{2 \log x}\sim 12 \cdot n queries.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <bits/stdc++.h>
using namespace std;

#define SZ(x) int(x.size())

const int MXN = 1003;

int n, k, p[MXN], q[MXN], cnt=0;

int ask() {
cout << "? ";
for(int i=1; i<=n; i++) cout << q[i] << ' ';
cout << endl;
int r;
cin >> r;
return r;
}

void ans() {
cout << "! ";
for(int i=1; i<=n; i++) cout << p[i] << ' ';
cout << endl;
}

bool mark[MXN];

void build(int i, vector<int> opt, vector<int> optbad) {
fill(mark+1, mark+n+1, 0);
fill(q+1, q+n+1, 0);
q[k] = i;
mark[i] = 1;
for(int j=1; j<k && !opt.empty(); j++) {
mark[q[j] = opt.back()] = 1;
opt.pop_back();
}
for(int j=n; !opt.empty(); j--) {
mark[q[j] = opt.back()] = 1;
opt.pop_back();
}
for(int j=k+1; !optbad.empty(); j++) {
mark[q[j] = optbad.back()] = 1;
optbad.pop_back();
}
for(int j=1; j<=n; j++)
if(!mark[j])
opt.push_back(j);
for(int j=1; j<=n; j++)
if(!q[j]) {
q[j] = opt.back();
opt.pop_back();
}
}

void rev() {
vector<int> vec;
for(int i=1; i<=n; i++)
if(i!=k)
vec.push_back(q[i]);
for(int i=1; i<=n; i++)
if(i!=k) {
q[i] = vec.back();
vec.pop_back();
}
}

void Main() {
cin >> n;
k = (n+1)/4+1;
cout << k << endl;
for(int i=1; i<=n; i++) {
vector<int> opt;
for(int j=1; j<=n; j++)
if(j!=i)
opt.push_back(j);
while(opt.size()>1) {
int sz = SZ(opt) - min((SZ(opt)+1)/2, n-(2*k-1));
build(i,
vector<int>(opt.begin(), opt.begin()+sz),
vector<int>(opt.begin()+sz, opt.end()));
int val = ask();
rev();
val += ask();
if(val==n-1) opt = vector<int>(opt.begin(), opt.begin()+sz);
else opt = vector<int>(opt.begin()+sz, opt.end());
}
p[opt.back()] = i;
}
ans();
}

int32_t main() {
int tc;
cin >> tc;
while(tc--) Main();
}

2127G2 - Inter Active (Hard Version)

Solution & Analysis: LMydd0225 and Error_Yuan
Preparation: _R00T and Hamed_Ghaffari

This version used an almost completely different approach from G1. Here’s the step-by-step analysis:

Analysis (Steps & Hints)

Step 0

Consider the following graph: ipii\to p_i. We will see the permutation as the graph.

When asking a permutation qq, the result is sum of whether q^{-1}(i)&lt;q^{-1}(p_i).

Hint 1.1

Why is there a condition about kk? If we do not have kk, can the permutation [2,1,4,3][2, 1, 4, 3] be guessed out?

Step 1.2

If there is a cycle of length 22 in the permutation graph (that is, pi=jp_i=j and pj=ip_j=i), exactly one of the two corresponding pairs to (pi,pj)(p_i, p_j) and (pj,pi)(p_j,p_i) will be counted in any query when we do not have kk. So we have to use kk for cycles of length 22. This inspires us to do casework on cycle length =2=2 or 3\ge 3.

Step 2.1

If the whole permutation graph is composed only of cycles of length 22, can you guess out the permutation in about 12nlogn\frac{1}{2}n\log n queries?

Hint 2.2

You need to use the property that the permutation graph is composed only of cycles of length 22.

Step 2.3

Let’s say you want to determine what is pip_i. Query any permutation qq with qk=iq_k=i. If pip_i is among q1,q2,,qk1q_1, q_2, \ldots, q_{k-1}, the response to the query will be n2\frac{n}{2}, otherwise, pip_i is among qk+1,qk+2,,qnq_{k+1}, q_{k+2}, \ldots, q_n, and the response will be n21\frac{n}{2}-1. You can verify this by yourself. Note that permutation graph is composed only of cycles of length 22.

Thus, we can put kk around n2\frac{n}{2} and apply binary search for a single ipii\to p_i with logn\log n queries. Note that when we get pi=jp_i=j, we also get pj=ip_j=i. So we only need 12nlogn\frac{1}{2}n\log n queries in total.

Step 3.1

How can we distinguish ipii\to p_i is in which kind of cycle, length of 22 or length 3\ge 3? Try to solve this for a single ii in 2logn2\log n queries. Note that you do not need to determine pip_i, you just need to tell whether ipii\to p_i is in a cycle of length 22.

Hint 3.2

If ipii\to p_i is in a cycle of length 3\ge 3, we have ll and jj such that lijl\to i\to j and ljl\ne j. Otherwise, l=jl=j.

Hint 3.3

Consider bitmasks.

Hint 3.4

Consider cyclic shifts. Do not use kk.

Step 3.5

Consider the following two queries (m&lt;k):

  1. [q1,q2,q3,,qm,,qk,][q_1, q_2, q_3, \ldots, q_m, \ldots, q_k, \ldots];
  2. [qm,q1,q2,,qm1,,qk,][q_m, q_1, q_2, \ldots, q_{m-1}, \ldots, q_k, \ldots].

Only the contribution of xqmyx\to q_m\to y may change: Let’s say A={q1,q2,,qm1}A=\{q_1,q_2,\ldots,q_{m-1}\}, B={qm+1,qm+2,qn}B=\{q_{m+1}, q_{m+2}, \ldots q_n\}. If xx and yy are both inside AA or both inside BB, responses to query 1. and 2. will be the same. Otherwise, answer changes by exactly 11. If the responses are different, we can next tell whether xix_i is in AA by looking at whether the difference is 11 or 1-1. However, if the responses are the same, we can’t tell whether they are both in AA or both in BB.

An idea to tell whether x=yx=y is to group numbers by their bitmasks. We can use logn\log n times such two queries to ask for each bit (let numbers with 0 on this bit in AA, those with 1 in BB). In the end, we will get xyx\oplus y. Then we surely get whether x=yx=y.

Hint 3.6

Step 3.5 needs 2logn2\log n queries for a single element. Can you use nlognn\log n queries to solve the problem in Step 3.5 for all elements? Note that we are doing cyclic shifts.

Step 3.7

Note that we are doing cyclic shifts. In fact, for each ii, we just need it to appear at q1q_1 and qmq_m respectively, without changing the set AA. Then, for a certain set AA, we can do cyclic shifts A|A| times to get all information we need. Similar for BB. Thus, we finished the task in Hint 3.6 in nlognn\log n queries.

Since we will fix kk around n2\frac{n}{2} for cycles with length 22, we must ensure that A|A| and B|B| are around n2\frac{n}{2}. But this is not always true. Fortunately, we can resolve this issue by assigning each integer an unqiue number cic_i, where 0ci2logn10\le c_i\le 2^{\lceil\log n\rceil}-1, so that there will be exactly n2\frac{n}{2} (or floor and ceil) 0s and 1s on each bit. We will group the indices by cic_i instead. Now we can put k=n2+1k=\lceil\frac{n}{2}\rceil+1.

Final Steps

Here are the final steps of this problem. First, we run the algorithm in Step 3. Now we get all xipix_i \oplus p_i, where xiipix_i\to i\to p_i holds.

First, we will determine all pip_i-s on cycles of length 3\ge 3. Note that we have determined all xipix_i\oplus p_i, so we only need to determine one edge for each cycle.

Note that in Step 3, when responses to two queries are different, we can know whether pip_i is in AA or xix_i is in AA. Note that we can change mm arbitrarily, so we can apply binary search on mm to get one of pip_i and xix_i. That finishes the task in logn\log n queries for each cycle. On average for each element, it is at most 13logn\frac{1}{3}\log n queries.

After that, we know all pip_i-s on cycles of length 3\ge 3, and we can calculate the response to any query [q1,q2,,qn][q_1, q_2,\ldots,q_n] easily if we don’t have kk. Similar to Step 2, we can determine all pip_i-s on cycles of length 22 in 12nlogn\frac{1}{2}n\log n queries. On average for each element, it is 12logn\frac{1}{2}\log n queries. Thus, in the worst case where the whole permutation graph consists only of cycles of length 22, the total number of queries is 1.5lognn1.5\lceil\log n\rceil\cdot n. When n=100n=100, it is 10.5n10.5\cdot n, a little larger than the limit. We can apply a trivial optimization when doing Step 2: do binary serach on possible indices instead of all indices. This will use a total of at most nlogn+i=0(n1)/2log(n12i)n\log n+\sum\limits_{i=0}^{\lfloor(n-1)/2\rfloor} \log(n-1-2\cdot i) queries. When n=100n=100, it is 986986, which fits the constraints well.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <bits/stdc++.h>
#define all(s) s.begin(), s.end()
using namespace std;
using ll = long long;
using ull = unsigned long long;

int T;

void solve() {
int n; cin >> n;
const int k = (n + 1) / 2;
const int M = __lg(n - 1) + 1;
cout << k + 1 << endl;

vector<int> p(n + 1);

auto query = [&](vector<int> &q) -> int {
cout << "? ";
for (int i = 1; i <= n; i++) cout << q[i] << " \n"[i == n];
cout.flush();
int res; cin >> res;
return res;
};

vector<int> c(n + 1), d(1 << M);
auto binary_coding = [&]() {
for (int i = 0, cnt = 1; cnt <= n; i++, cnt++) {
c[cnt++] = i;
if (cnt <= n) c[cnt] = (1 << M) - 1 - i;
}
for (int i = 1; i <= n; i++) d[c[i]] = i;
return;
};

vector<int> xors(n + 1);
vector<vector<int>> res1(M, vector<int>(n + 1)), res2(M, vector<int>(n + 1));
vector<int> good, bad;
auto getXORs = [&]() {
for (int bit = 0; bit < M; bit++) {
vector<int> A, B;
for (int i = 1; i <= n; i++) {
if (c[i] & (1 << bit)) B.emplace_back(i);
else A.emplace_back(i);
}
int m = A.size(), l = B.size();
for (int i = 0; i < m; i++) {
vector<int> q(n + 1);
for (int j = 0; j < m; j++) q[j + 1] = A[(j + i) % m];
for (int j = 0; j < l; j++) q[j + m + 1] = B[j];
int res = query(q);
res1[bit][q[1]] = res;
res2[bit][q[m]] = res;
}
for (int i = 0; i < l; i++) {
vector<int> q(n + 1);
for (int j = 0; j < l; j++) q[j + 1] = B[(j + i) % l];
for (int j = 0; j < m; j++) q[j + l + 1] = A[j];
int res = query(q);
res1[bit][q[1]] = res;
res2[bit][q[l]] = res;
}
for (int i = 1; i <= n; i++) {
if (res1[bit][i] != res2[bit][i]) xors[i] ^= (1 << bit);
}
}
for (int i = 1; i <= n; i++) {
if (xors[i] != 0) good.emplace_back(i);
else bad.emplace_back(i);
}
return;
};
auto solve3 = [&]() {
for (auto pos : good) {
if (p[pos]) continue;
int x = xors[pos], bit = __lg(x & (-x));
vector<int> A, B;
for (int i = 1; i <= n; i++) {
if (c[i] & (1 << bit)) B.emplace_back(i);
else A.emplace_back(i);
}
if (c[pos] & (1 << bit)) swap(A, B);
int m = A.size(), l = B.size();
int id = 0;
for (int i = 0; i < m; i++) if (A[i] == pos) id = i;
int L = 2, R = m;
vector<int> base(n + 1);
for (int j = 0; j < m; j++) base[j + 1] = A[(j + id) % m];
for (int j = 0; j < l; j++) base[j + m + 1] = B[j];
while (L < R) {
int mid = (L + R) >> 1;
vector<int> q(n + 1);
for (int i = 1; i < mid; i++) q[i] = base[i + 1];
q[mid] = base[1];
for (int i = mid + 1; i <= n; i++) q[i] = base[i];
int res = query(q);
if (res != res1[bit][pos]) R = mid;
else L = mid + 1;
}
int s = 0;
if (res2[bit][pos] > res1[bit][pos]) p[base[L]] = pos, s = base[L];
else p[pos] = base[L], s = pos;
while (!p[p[s]]) {
int X = xors[p[s]];
p[p[s]] = d[X ^ c[s]];
s = p[s];
}
}
};
auto solve2 = [&]() {
for (auto pos : bad) {
if (p[pos]) continue;
auto calc = [&](vector<int> &q) {
int val = count(all(p), 0) / 2;
vector<int> inv(n + 1);
for (int i = 1; i <= n; i++) inv[q[i]] = i;
for (int i = 1; i <= n; i++) val += (inv[i] < inv[p[i]]);
return val;
};
vector<int> cand, ok;
for (int i = 1; i <= n; i++) {
if (i != pos && !p[i]) cand.emplace_back(i);
if (p[i]) ok.emplace_back(i);
}
while ((int)cand.size() != 1) {
vector<int> q = { 0 }, L, R;
int len = ((int)cand.size() + 1) / 2;
for (int i = 0; i < len; i++) q.emplace_back(cand[i]), L.emplace_back(cand[i]);
for (int i = len; i < k; i++) q.emplace_back(ok[i - len]);
q.emplace_back(pos);
for (int i = len; i < (int)cand.size(); i++) q.emplace_back(cand[i]), R.emplace_back(cand[i]);
for (int i = k - len; i < (int)ok.size(); i++) q.emplace_back(ok[i]);
int res = query(q);
res -= calc(q);
if (res != 0) swap(L, R);
cand = L;
for (auto x : R) ok.emplace_back(x);
}
p[pos] = cand[0];
p[cand[0]] = pos;
}
};

binary_coding();
getXORs();
solve3();
solve2();

cout << "! ";
for (int i = 1; i <= n; i++) cout << p[i] << " \n"[i == n];
cout.flush();
return;
}

int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> T;
while (T--) {
solve();
}
}

2127H - 23 Rises Again

Idea: sweetweasel and eren__
Preparation: Hamed_Ghaffari and _R00T

Hints

Hint 0

Each connected component of a candy graph is either a simple path or a simple cycle.

Hint 1

Try to break the problem down into smaller parts.

Hint 2

Take a DFS tree, at most 55 back-edges pass through each vertex.

Hint 3

Choose a vertex vv, brute force on the back-edges that pass through vv and appears in the subgraph with maximum number of edges, then remove vv and all back-edges that pass through vv.

Hint 4

Now we have to solve the following sub-problem for each connected component:

You are given a simple connected graph that each vertex belongs to at most 55 simple cycles, and an array d1,d2,,dn(0di2)d_1,d_2,\ldots,d_n (0 \leq d_i \leq 2). What is the subgraph with maximum number of edges that degree of vertex ii is at most did_i.

Hint 5

The sub-problem can be solved in O(2nnm)\mathcal{O}(2^nnm) with dp bitmask.

Hint 6

Let NN be the size of the component with the maximum size after removing vv and back-edges that pass through vv.

We can solve the problem in O(252NNm)\mathcal{O}(2^5 2^NNm).

Hint 7

Choose vv as the centroid of the DFS tree.

Since Nn/2N \leq n/2 the complexity will be O(252n/2nm)\mathcal{O}(2^5 2^{n/2}nm).

Hint 8

Is the complexity really O(252n/2nm)\mathcal{O}(2^5 2^{n/2}nm)?

Solution

Each connected component of a candy graph is either a simple path or a simple cycle.

Take a DFS tree, at most 55 back-edges pass through each vertex, then choose a vertex vv, brute force on the back-edges that pass through vv and appears in the subgraph with maximum number of edges, then remove vv and all back-edges that pass through vv.

Let did_i be the maximum degree that vertex ii can have. Initially di=2d_i=2 for each vertex. Each back-edge (x,y)(x,y) that you select, reduces dxd_x and dyd_y by 11. If after selecting back-edges that pass through vv, there exists a vertex with negative dd, skip this case. Otherwise you have to solve the sub-problem in Hint 4 for every connected component.

We can solve the sub-problem with the following dp bitmask:

Let ansmaskans_{mask} be the answer for maskmask, and let dpmask,u,v,l1dp_{mask,u,v,l1} be the answer for maskmask where the last path we selected is from uu to vv and l1 0, 1 l1 \in \text{ {0, 1} } means that the length of the path is 11 or not.

Transitions:

  • Start a new path: ansmask+1dpmask,u,v,1ans_{mask}+1 \to dp_{mask,u,v,1}, if (u,v)(u,v) is an edge outside maskmask with du,dv1d_u, d_v \geq 1.
  • Add a vertex to the last path: dpmask,u,v,l1+1dpmask+2w,u,w,0dp_{mask,u,v,l1}+1 \to dp_{mask+2^w,u,w,0}, if ww is a vertex outside maskmask and adjacent to vv, and dv=2,dw1d_v = 2, d_w \geq 1.
  • Make the last path cycle: dpmask,u,v,0+1ansmaskdp_{mask,u,v,0}+1 \to ans_{mask}, if there exists a (u,v)(u, v) edge, and du=dv=2d_u = d_v = 2.
  • Skip a vertex: ansmaskansmask+2wans_{mask} \to ans_{mask+2^w}, if ww is a vertex outside maskmask.

Also, you have to solve the sub-problem for each component twice, because you can choose a DFS tree edge connected to the vertex that you’ve deleted and it reduces dd of one vertex in that component.

It can be seen that if NN be the size of the component with the maximum size, the complexity will be O(2NNm)\mathcal{O}(2^NNm) for a fixed set of back-edges, and O(252NNm)\mathcal{O}(2^52^NNm) in total.

If we select vv as the centroid of the DFS tree NN will be less than or equal to n/2n/2 so the complexity will be O(252n/2nm)\mathcal{O}(2^5 2^{n/2}nm).

It can be proven that m3nm \leq 3n in graphs that each vertex belongs to at most 55 simple cycles. So the complexity will be O(252n/2n2)\mathcal{O}(2^52^{n/2}n^2).

Proof

We prove this by induction. suppose that m3nm \leq 3n for all graphs with n<Nn \lt N.

Take a DFS tree, we can prove that the degree of a leaf is at most 33, because otherwise at least 33 back-edges would exit that leaf and there would be at least 66 cycles containing that leaf.

So there always exists a vertex with degree 3\leq 3, we can remove it, m3(N1)+3=3Nm \leq 3(N-1) + 3 = 3N.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <bits/stdc++.h>
using namespace std;

#define SZ(x) int(x.size())
#define maxs(a, b) (a = max(a, b))

const int MXN = 30, MXM = MXN*(MXN-1)/2;

int n, m, U[MXM], V[MXM];
vector<int> g[MXN];
bool tedge[MXM], have_edge[MXN][MXN];
int sz[MXN];

void dfs1(int v) {
sz[v] = 1;
for(int i : g[v]) {
int u = v^U[i]^V[i];
if(!sz[u]) {
tedge[i] = 1;
dfs1(u);
sz[v] += sz[u];
}
}
}

int centroid(int v, int p=-1) {
for(int i : g[v]) if(tedge[i]) {
int u = v^U[i]^V[i];
if(u!=p && sz[u]+sz[u]>n)
return centroid(u, v);
}
return v;
}

int ID[MXN], id_counter;
vector<int> vertices[MXN];
int dp[1<<(MXN>>1)][MXN>>1][MXN>>1][2], ans_tmp[1<<(MXN>>1)], ans[2];

void dfs_id(int v, int p=-1) {
vertices[ID[v] = id_counter].push_back(v);
for(int i : g[v]) if(tedge[i]) {
int u = v^U[i]^V[i];
if(u!=p) dfs_id(u, v);
}
}

int deg[MXN], pos[MXN];

int solve_(int id) {
int n = SZ(vertices[id]);
for(int msk=0; msk<(1<<n); msk++) {
ans_tmp[msk] = -1e9;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
for(int x : {0,1})
dp[msk][i][j][x] = -1e9;
}
ans_tmp[0] = 0;
for(int msk=0; msk<(1<<n); msk++) {
for(int i=0; i<n; i++) if(msk>>i&1)
for(int j=0; j<n; j++) if(i!=j && (msk>>j&1)) {
if(deg[vertices[id][j]]==2) {
for(int eid : g[vertices[id][j]]) if(ID[U[eid]]==ID[V[eid]]) {
int u = vertices[id][j]^U[eid]^V[eid];
if(!(msk>>pos[u]&1) && deg[u]>=1)
maxs(dp[msk^(1<<pos[u])][i][pos[u]][0],
max(dp[msk][i][j][0], dp[msk][i][j][1])+1);
}
if(deg[vertices[id][i]]==2 && have_edge[vertices[id][i]][vertices[id][j]])
maxs(ans_tmp[msk], dp[msk][i][j][0]+1);
}
maxs(ans_tmp[msk], max(dp[msk][i][j][0], dp[msk][i][j][1]));
}
for(int i=0; i<n; i++) if(!(msk>>i&1)) {
maxs(ans_tmp[msk^(1<<i)], ans_tmp[msk]);
if(deg[vertices[id][i]]>=1)
for(int eid : g[vertices[id][i]]) if(ID[U[eid]]==ID[V[eid]]) {
int u = vertices[id][i]^U[eid]^V[eid];
if(deg[u]>=1 && !(msk>>pos[u]&1))
maxs(dp[msk^(1<<i)^(1<<pos[u])][i][pos[u]][1], ans_tmp[msk]+1);
}
}
}
return ans_tmp[(1<<n)-1];
}

void solve(int id, int cent_neighbour) {
ans[0] = solve_(id);
if(deg[cent_neighbour]!=0) {
deg[cent_neighbour]--;
ans[1] = solve_(id);
}
else ans[1] = -1e9;
}

void Main() {
cin >> n >> m;
for(int i=0; i<n; i++) {
g[i].clear();
vertices[i].clear();
sz[i] = 0;
for(int j=0; j<n; j++)
have_edge[i][j] = 0;
}
for(int i=0; i<m; i++) {
tedge[i] = 0;
}
for(int i=0,u,v; i<m; i++) {
cin >> u >> v;
u--, v--;
have_edge[u][v] = have_edge[v][u] = 1;
U[i] = u;
V[i] = v;
g[u].push_back(i);
g[v].push_back(i);
}
dfs1(0);
int cent = centroid(0);

ID[cent] = 0;
id_counter = 0;
for(int i : g[cent]) if(tedge[i]) {
int u = cent^U[i]^V[i];
id_counter++;
dfs_id(u, cent);
for(int j=0; j<SZ(vertices[id_counter]); j++)
pos[vertices[id_counter][j]] = j;
}

vector<int> be;
for(int i=0; i<m; i++)
if(!tedge[i] && (ID[U[i]]^ID[V[i]])) be.push_back(i);

int besz = SZ(be), answer = -1e9;

for(int msk=0; msk<(1<<besz); msk++) {
fill(deg, deg+n, 2);
for(int i=0; i<besz; i++) if(msk>>i&1)
deg[U[be[i]]]--, deg[V[be[i]]]--;
bool deg3 = 0;
for(int i=0; i<n; i++)
if(deg[i]<0) {
deg3 = 1;
break;
}
if(deg3) continue;
int cur[3];
cur[0] = cur[1] = cur[2] = -1e9;
cur[deg[cent]] = __builtin_popcount(msk);
for(int i : g[cent]) if(tedge[i]) {
int u = cent^U[i]^V[i];
solve(ID[u], u);
cur[0] = max(cur[0]+ans[0], cur[1]+ans[1]+1);
cur[1] = max(cur[1]+ans[0], cur[2]+ans[1]+1);
cur[2] = cur[2]+ans[0];
}
answer = max({answer, cur[0], cur[1], cur[2]});
}
cout << answer << '\n';
}

int32_t main() {
cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);
int tc;
cin >> tc;
while(tc--) Main();
return 0;
}

Apology

It turns out there are some very simple randomized solutions we hadn’t anticipated, as well as approaches using matching and even unexpected ones like backtracking. Unfortunately, these are quite hard to detect and reject without knowing beforehand.

We sincerely apologize for this mistake. We hope you enjoyed the rest of the problems.